blob: 8254347708f964acf514227d3995e15bc84067d0 [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>
Nick Wellnhoferd422b952017-10-09 13:37:42 +020015#include <stddef.h>
Daniel Veillard92727042002-09-17 17:59:20 +000016#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000017#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000018#endif
19
Owen Taylor3473f882001-02-23 17:55:21 +000020
21#ifdef HAVE_SYS_TYPES_H
22#include <sys/types.h>
23#endif
24#ifdef HAVE_SYS_STAT_H
25#include <sys/stat.h>
26#endif
27#ifdef HAVE_FCNTL_H
28#include <fcntl.h>
29#endif
30#ifdef HAVE_UNISTD_H
31#include <unistd.h>
32#endif
33#ifdef HAVE_STDLIB_H
34#include <stdlib.h>
35#endif
Nick Wellnhofercb5541c2017-11-13 17:08:38 +010036#ifdef LIBXML_ZLIB_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +000037#include <zlib.h>
38#endif
Nick Wellnhofercb5541c2017-11-13 17:08:38 +010039#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +020040#include <lzma.h>
41#endif
Owen Taylor3473f882001-02-23 17:55:21 +000042
Nick Wellnhofere3890542017-10-09 00:20:01 +020043#if defined(_WIN32) && !defined(__CYGWIN__)
44#define WIN32_LEAN_AND_MEAN
Daniel Veillardf7416012006-04-27 08:15:20 +000045#include <windows.h>
46#endif
47
Daniel Veillard59d3ed82007-04-17 12:44:58 +000048#if defined(_WIN32_WCE)
49#include <winnls.h> /* for CP_UTF8 */
50#endif
51
Nick Wellnhofer56723972017-10-09 15:35:32 +020052#ifndef S_ISDIR
53# ifdef _S_ISDIR
54# define S_ISDIR(x) _S_ISDIR(x)
55# elif defined(S_IFDIR)
56# ifdef S_IFMT
57# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
58# elif defined(_S_IFMT)
59# define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
Owen Taylor3473f882001-02-23 17:55:21 +000060# endif
61# endif
62#endif
63
64#include <libxml/xmlmemory.h>
65#include <libxml/parser.h>
66#include <libxml/parserInternals.h>
67#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000068#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000069#include <libxml/nanohttp.h>
70#include <libxml/nanoftp.h>
71#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000072#ifdef LIBXML_CATALOG_ENABLED
73#include <libxml/catalog.h>
74#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000075#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000076
Daniel Veillarda6a6e702012-07-16 14:22:54 +080077#include "buf.h"
78#include "enc.h"
79
Daniel Veillardf012a642001-07-23 19:10:52 +000080/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000081/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000082/* #define DEBUG_INPUT */
83
84#ifdef DEBUG_INPUT
85#define MINLEN 40
86#else
87#define MINLEN 4000
88#endif
89
90/*
91 * Input I/O callback sets
92 */
93typedef struct _xmlInputCallback {
94 xmlInputMatchCallback matchcallback;
95 xmlInputOpenCallback opencallback;
96 xmlInputReadCallback readcallback;
97 xmlInputCloseCallback closecallback;
98} xmlInputCallback;
99
100#define MAX_INPUT_CALLBACK 15
101
Daniel Veillard22090732001-07-16 00:06:07 +0000102static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
103static int xmlInputCallbackNr = 0;
104static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000105
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000106#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000107/*
108 * Output I/O callback sets
109 */
110typedef struct _xmlOutputCallback {
111 xmlOutputMatchCallback matchcallback;
112 xmlOutputOpenCallback opencallback;
113 xmlOutputWriteCallback writecallback;
114 xmlOutputCloseCallback closecallback;
115} xmlOutputCallback;
116
117#define MAX_OUTPUT_CALLBACK 15
118
Daniel Veillard22090732001-07-16 00:06:07 +0000119static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
120static int xmlOutputCallbackNr = 0;
121static int xmlOutputCallbackInitialized = 0;
Daniel Veillardda3fee42008-09-01 13:08:57 +0000122
123xmlOutputBufferPtr
124xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000125#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000126
Daniel Veillard05d987b2003-10-08 11:54:57 +0000127/************************************************************************
128 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200129 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000130 * *
131 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000132
Daniel Veillard05d987b2003-10-08 11:54:57 +0000133static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000134 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000135 "Permission denied", /* EACCES */
136 "Resource temporarily unavailable",/* EAGAIN */
137 "Bad file descriptor", /* EBADF */
138 "Bad message", /* EBADMSG */
139 "Resource busy", /* EBUSY */
140 "Operation canceled", /* ECANCELED */
141 "No child processes", /* ECHILD */
142 "Resource deadlock avoided",/* EDEADLK */
143 "Domain error", /* EDOM */
144 "File exists", /* EEXIST */
145 "Bad address", /* EFAULT */
146 "File too large", /* EFBIG */
147 "Operation in progress", /* EINPROGRESS */
148 "Interrupted function call",/* EINTR */
149 "Invalid argument", /* EINVAL */
150 "Input/output error", /* EIO */
151 "Is a directory", /* EISDIR */
152 "Too many open files", /* EMFILE */
153 "Too many links", /* EMLINK */
154 "Inappropriate message buffer length",/* EMSGSIZE */
155 "Filename too long", /* ENAMETOOLONG */
156 "Too many open files in system",/* ENFILE */
157 "No such device", /* ENODEV */
158 "No such file or directory",/* ENOENT */
159 "Exec format error", /* ENOEXEC */
160 "No locks available", /* ENOLCK */
161 "Not enough space", /* ENOMEM */
162 "No space left on device", /* ENOSPC */
163 "Function not implemented", /* ENOSYS */
164 "Not a directory", /* ENOTDIR */
165 "Directory not empty", /* ENOTEMPTY */
166 "Not supported", /* ENOTSUP */
167 "Inappropriate I/O control operation",/* ENOTTY */
168 "No such device or address",/* ENXIO */
169 "Operation not permitted", /* EPERM */
170 "Broken pipe", /* EPIPE */
171 "Result too large", /* ERANGE */
172 "Read-only file system", /* EROFS */
173 "Invalid seek", /* ESPIPE */
174 "No such process", /* ESRCH */
175 "Operation timed out", /* ETIMEDOUT */
176 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000177 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000178 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000179 "flush error",
180 "write error",
181 "no input",
182 "buffer full",
183 "loading error",
184 "not a socket", /* ENOTSOCK */
185 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000186 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000187 "unreachable network", /* ENETUNREACH */
188 "adddress in use", /* EADDRINUSE */
189 "already in use", /* EALREADY */
190 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000191};
192
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000193#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000194/**
195 * __xmlIOWin32UTF8ToWChar:
196 * @u8String: uft-8 string
197 *
198 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
199 */
200static wchar_t *
201__xmlIOWin32UTF8ToWChar(const char *u8String)
202{
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000203 wchar_t *wString = NULL;
Daniel Veillardf7416012006-04-27 08:15:20 +0000204
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000205 if (u8String) {
206 int wLen =
207 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
208 -1, NULL, 0);
209 if (wLen) {
210 wString = xmlMalloc(wLen * sizeof(wchar_t));
211 if (wString) {
212 if (MultiByteToWideChar
213 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
214 xmlFree(wString);
215 wString = NULL;
216 }
217 }
218 }
219 }
220
221 return wString;
Daniel Veillardf7416012006-04-27 08:15:20 +0000222}
223#endif
224
Daniel Veillard05d987b2003-10-08 11:54:57 +0000225/**
226 * xmlIOErrMemory:
227 * @extra: extra informations
228 *
229 * Handle an out of memory condition
230 */
231static void
232xmlIOErrMemory(const char *extra)
233{
234 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
235}
236
237/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000238 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000239 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000240 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000241 * @extra: extra informations
242 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000243 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000244 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000245void
246__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000247{
248 unsigned int idx;
249
250 if (code == 0) {
251#ifdef HAVE_ERRNO_H
252 if (errno == 0) code = 0;
253#ifdef EACCES
254 else if (errno == EACCES) code = XML_IO_EACCES;
255#endif
256#ifdef EAGAIN
257 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
258#endif
259#ifdef EBADF
260 else if (errno == EBADF) code = XML_IO_EBADF;
261#endif
262#ifdef EBADMSG
263 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
264#endif
265#ifdef EBUSY
266 else if (errno == EBUSY) code = XML_IO_EBUSY;
267#endif
268#ifdef ECANCELED
269 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
270#endif
271#ifdef ECHILD
272 else if (errno == ECHILD) code = XML_IO_ECHILD;
273#endif
274#ifdef EDEADLK
275 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
276#endif
277#ifdef EDOM
278 else if (errno == EDOM) code = XML_IO_EDOM;
279#endif
280#ifdef EEXIST
281 else if (errno == EEXIST) code = XML_IO_EEXIST;
282#endif
283#ifdef EFAULT
284 else if (errno == EFAULT) code = XML_IO_EFAULT;
285#endif
286#ifdef EFBIG
287 else if (errno == EFBIG) code = XML_IO_EFBIG;
288#endif
289#ifdef EINPROGRESS
290 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
291#endif
292#ifdef EINTR
293 else if (errno == EINTR) code = XML_IO_EINTR;
294#endif
295#ifdef EINVAL
296 else if (errno == EINVAL) code = XML_IO_EINVAL;
297#endif
298#ifdef EIO
299 else if (errno == EIO) code = XML_IO_EIO;
300#endif
301#ifdef EISDIR
302 else if (errno == EISDIR) code = XML_IO_EISDIR;
303#endif
304#ifdef EMFILE
305 else if (errno == EMFILE) code = XML_IO_EMFILE;
306#endif
307#ifdef EMLINK
308 else if (errno == EMLINK) code = XML_IO_EMLINK;
309#endif
310#ifdef EMSGSIZE
311 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
312#endif
313#ifdef ENAMETOOLONG
314 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
315#endif
316#ifdef ENFILE
317 else if (errno == ENFILE) code = XML_IO_ENFILE;
318#endif
319#ifdef ENODEV
320 else if (errno == ENODEV) code = XML_IO_ENODEV;
321#endif
322#ifdef ENOENT
323 else if (errno == ENOENT) code = XML_IO_ENOENT;
324#endif
325#ifdef ENOEXEC
326 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
327#endif
328#ifdef ENOLCK
329 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
330#endif
331#ifdef ENOMEM
332 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
333#endif
334#ifdef ENOSPC
335 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
336#endif
337#ifdef ENOSYS
338 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
339#endif
340#ifdef ENOTDIR
341 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
342#endif
343#ifdef ENOTEMPTY
344 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
345#endif
346#ifdef ENOTSUP
347 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
348#endif
349#ifdef ENOTTY
350 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
351#endif
352#ifdef ENXIO
353 else if (errno == ENXIO) code = XML_IO_ENXIO;
354#endif
355#ifdef EPERM
356 else if (errno == EPERM) code = XML_IO_EPERM;
357#endif
358#ifdef EPIPE
359 else if (errno == EPIPE) code = XML_IO_EPIPE;
360#endif
361#ifdef ERANGE
362 else if (errno == ERANGE) code = XML_IO_ERANGE;
363#endif
364#ifdef EROFS
365 else if (errno == EROFS) code = XML_IO_EROFS;
366#endif
367#ifdef ESPIPE
368 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
369#endif
370#ifdef ESRCH
371 else if (errno == ESRCH) code = XML_IO_ESRCH;
372#endif
373#ifdef ETIMEDOUT
374 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
375#endif
376#ifdef EXDEV
377 else if (errno == EXDEV) code = XML_IO_EXDEV;
378#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000379#ifdef ENOTSOCK
380 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
381#endif
382#ifdef EISCONN
383 else if (errno == EISCONN) code = XML_IO_EISCONN;
384#endif
385#ifdef ECONNREFUSED
386 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
387#endif
388#ifdef ETIMEDOUT
389 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
390#endif
391#ifdef ENETUNREACH
392 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
393#endif
394#ifdef EADDRINUSE
395 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
396#endif
397#ifdef EINPROGRESS
398 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
399#endif
400#ifdef EALREADY
401 else if (errno == EALREADY) code = XML_IO_EALREADY;
402#endif
403#ifdef EAFNOSUPPORT
404 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
405#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000406 else code = XML_IO_UNKNOWN;
407#endif /* HAVE_ERRNO_H */
408 }
409 idx = 0;
410 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
411 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200412
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000413 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
414}
415
416/**
417 * xmlIOErr:
418 * @code: the error number
419 * @extra: extra informations
420 *
421 * Handle an I/O error
422 */
423static void
424xmlIOErr(int code, const char *extra)
425{
426 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000427}
428
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000429/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000430 * __xmlLoaderErr:
431 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000432 * @extra: extra informations
433 *
434 * Handle a resource access error
435 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000436void
437__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000438{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000439 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000440 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000441 xmlGenericErrorFunc channel = NULL;
442 void *data = NULL;
443 xmlErrorLevel level = XML_ERR_ERROR;
444
Daniel Veillard157fee02003-10-31 10:36:03 +0000445 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
446 (ctxt->instate == XML_PARSER_EOF))
447 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000448 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
449 if (ctxt->validate) {
450 channel = ctxt->sax->error;
451 level = XML_ERR_ERROR;
452 } else {
453 channel = ctxt->sax->warning;
454 level = XML_ERR_WARNING;
455 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000456 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
457 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000458 data = ctxt->userData;
459 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000460 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000461 XML_IO_LOAD_ERROR, level, NULL, 0,
462 filename, NULL, NULL, 0, 0,
463 msg, filename);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200464
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000465}
466
Daniel Veillard05d987b2003-10-08 11:54:57 +0000467/************************************************************************
468 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200469 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000470 * *
471 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000472/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000473 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000474 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000475 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000476 * This function is obsolete. Please see xmlURIFromPath in uri.c for
477 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000478 *
479 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000480 */
481xmlChar *
482xmlNormalizeWindowsPath(const xmlChar *path)
483{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000484 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000485}
486
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000487/**
488 * xmlCleanupInputCallbacks:
489 *
490 * clears the entire input callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200491 * compiled-in I/O.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000492 */
493void
494xmlCleanupInputCallbacks(void)
495{
496 int i;
497
498 if (!xmlInputCallbackInitialized)
499 return;
500
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000501 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000502 xmlInputCallbackTable[i].matchcallback = NULL;
503 xmlInputCallbackTable[i].opencallback = NULL;
504 xmlInputCallbackTable[i].readcallback = NULL;
505 xmlInputCallbackTable[i].closecallback = NULL;
506 }
507
508 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000509 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000510}
511
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000512/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000513 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000514 *
515 * Clear the top input callback from the input stack. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200516 * compiled-in I/O.
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000517 *
518 * Returns the number of input callback registered or -1 in case of error.
519 */
520int
521xmlPopInputCallbacks(void)
522{
523 if (!xmlInputCallbackInitialized)
524 return(-1);
525
526 if (xmlInputCallbackNr <= 0)
527 return(-1);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200528
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000529 xmlInputCallbackNr--;
530 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
531 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
532 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
533 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
534
535 return(xmlInputCallbackNr);
536}
537
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000538#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000539/**
540 * xmlCleanupOutputCallbacks:
541 *
542 * clears the entire output callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200543 * compiled-in I/O callbacks.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000544 */
545void
546xmlCleanupOutputCallbacks(void)
547{
548 int i;
549
550 if (!xmlOutputCallbackInitialized)
551 return;
552
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000553 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000554 xmlOutputCallbackTable[i].matchcallback = NULL;
555 xmlOutputCallbackTable[i].opencallback = NULL;
556 xmlOutputCallbackTable[i].writecallback = NULL;
557 xmlOutputCallbackTable[i].closecallback = NULL;
558 }
559
560 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000561 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000562}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000563#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000564
Owen Taylor3473f882001-02-23 17:55:21 +0000565/************************************************************************
566 * *
567 * Standard I/O for file accesses *
568 * *
569 ************************************************************************/
570
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000571#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
572
573/**
574 * xmlWrapOpenUtf8:
575 * @path: the path in utf-8 encoding
576 * @mode: type of access (0 - read, 1 - write)
577 *
578 * function opens the file specified by @path
579 *
580 */
581static FILE*
582xmlWrapOpenUtf8(const char *path,int mode)
583{
584 FILE *fd = NULL;
585 wchar_t *wPath;
586
587 wPath = __xmlIOWin32UTF8ToWChar(path);
588 if(wPath)
589 {
590 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
591 xmlFree(wPath);
592 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000593 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000594 if(fd == NULL)
595 fd = fopen(path, mode ? "wb" : "rb");
596
597 return fd;
598}
599
Nick Wellnhofercb5541c2017-11-13 17:08:38 +0100600#ifdef LIBXML_ZLIB_ENABLED
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200601static gzFile
602xmlWrapGzOpenUtf8(const char *path, const char *mode)
603{
604 gzFile fd;
605 wchar_t *wPath;
606
607 fd = gzopen (path, mode);
608 if (fd)
609 return fd;
610
611 wPath = __xmlIOWin32UTF8ToWChar(path);
612 if(wPath)
613 {
614 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
615#ifdef _O_BINARY
616 m |= (strstr(mode, "b") ? _O_BINARY : 0);
617#endif
618 d = _wopen(wPath, m);
619 if (d >= 0)
620 fd = gzdopen(d, mode);
621 xmlFree(wPath);
622 }
623
624 return fd;
625}
Rob Richards6c61e022009-08-12 11:41:27 -0400626#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200627
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000628/**
629 * xmlWrapStatUtf8:
630 * @path: the path in utf-8 encoding
631 * @info: structure that stores results
632 *
633 * function obtains information about the file or directory
634 *
635 */
636static int
Nick Wellnhofer56723972017-10-09 15:35:32 +0200637xmlWrapStatUtf8(const char *path, struct _stat *info) {
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000638 int retval = -1;
639 wchar_t *wPath;
640
641 wPath = __xmlIOWin32UTF8ToWChar(path);
Nick Wellnhofer56723972017-10-09 15:35:32 +0200642 if (wPath) {
643 retval = _wstat(wPath, info);
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000644 xmlFree(wPath);
645 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000646 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000647 if(retval < 0)
Nick Wellnhofer56723972017-10-09 15:35:32 +0200648 retval = _stat(path, info);
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000649 return retval;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000650}
651
652#endif
653
Owen Taylor3473f882001-02-23 17:55:21 +0000654/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000655 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000656 * @path: the path to check
657 *
658 * function checks to see if @path is a valid source
659 * (file, socket...) for XML.
660 *
661 * if stat is not available on the target machine,
662 * returns 1. if stat fails, returns 0 (if calling
663 * stat on the filename fails, it can't be right).
664 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000665 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000666 */
667
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000668int
Owen Taylor3473f882001-02-23 17:55:21 +0000669xmlCheckFilename (const char *path)
670{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000671#ifdef HAVE_STAT
Nick Wellnhofer56723972017-10-09 15:35:32 +0200672#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
673 struct _stat stat_buffer;
674#else
Michael Stahl55b899a2012-09-07 12:14:00 +0800675 struct stat stat_buffer;
Daniel Veillard0b309952006-05-02 20:34:38 +0000676#endif
Nick Wellnhofer56723972017-10-09 15:35:32 +0200677#endif
Michael Stahl55b899a2012-09-07 12:14:00 +0800678 if (path == NULL)
679 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000680
Owen Taylor3473f882001-02-23 17:55:21 +0000681#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000682#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Michael Stahl55b899a2012-09-07 12:14:00 +0800683 /*
684 * On Windows stat and wstat do not work with long pathname,
685 * which start with '\\?\'
686 */
687 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
688 (path[3] == '\\') )
689 return 1;
690
Nick Wellnhofer56723972017-10-09 15:35:32 +0200691 if (xmlWrapStatUtf8(path, &stat_buffer) == -1)
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000692 return 0;
693#else
Owen Taylor3473f882001-02-23 17:55:21 +0000694 if (stat(path, &stat_buffer) == -1)
695 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000696#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000697#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000698 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000699 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000700#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000701#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000702 return 1;
703}
704
Daniel Veillard7a72f4a2014-10-13 16:23:24 +0800705/**
Vlad Tsyrklevich28f52fe2017-08-10 15:08:48 -0700706 * xmlInputReadCallbackNop:
Daniel Veillard7a72f4a2014-10-13 16:23:24 +0800707 *
Vlad Tsyrklevich28f52fe2017-08-10 15:08:48 -0700708 * No Operation xmlInputReadCallback function, does nothing.
Daniel Veillard7a72f4a2014-10-13 16:23:24 +0800709 *
710 * Returns zero
711 */
Daniel Veillard153cf152012-10-26 13:50:47 +0800712int
Vlad Tsyrklevich28f52fe2017-08-10 15:08:48 -0700713xmlInputReadCallbackNop(void *context ATTRIBUTE_UNUSED,
714 char *buffer ATTRIBUTE_UNUSED,
715 int len ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000716 return(0);
717}
718
719/**
Owen Taylor3473f882001-02-23 17:55:21 +0000720 * xmlFdRead:
721 * @context: the I/O context
722 * @buffer: where to drop data
723 * @len: number of bytes to read
724 *
725 * Read @len bytes to @buffer from the I/O channel.
726 *
727 * Returns the number of bytes written
728 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000729static int
Owen Taylor3473f882001-02-23 17:55:21 +0000730xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000731 int ret;
732
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200733 ret = read((int) (ptrdiff_t) context, &buffer[0], len);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000734 if (ret < 0) xmlIOErr(0, "read()");
735 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000736}
737
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000738#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000739/**
740 * xmlFdWrite:
741 * @context: the I/O context
742 * @buffer: where to get data
743 * @len: number of bytes to write
744 *
745 * Write @len bytes from @buffer to the I/O channel.
746 *
747 * Returns the number of bytes written
748 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000749static int
Owen Taylor3473f882001-02-23 17:55:21 +0000750xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000751 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000752
Daniel Veillard9b693b42005-10-28 14:54:17 +0000753 if (len > 0) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200754 ret = write((int) (ptrdiff_t) context, &buffer[0], len);
Daniel Veillard9b693b42005-10-28 14:54:17 +0000755 if (ret < 0) xmlIOErr(0, "write()");
756 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000757 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000758}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000759#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000760
761/**
762 * xmlFdClose:
763 * @context: the I/O context
764 *
765 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000766 *
767 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000768 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000769static int
Owen Taylor3473f882001-02-23 17:55:21 +0000770xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000771 int ret;
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200772 ret = close((int) (ptrdiff_t) context);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000773 if (ret < 0) xmlIOErr(0, "close()");
774 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000775}
776
777/**
778 * xmlFileMatch:
779 * @filename: the URI for matching
780 *
781 * input from FILE *
782 *
783 * Returns 1 if matches, 0 otherwise
784 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000785int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000786xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000787 return(1);
788}
789
790/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000791 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000792 * @filename: the URI for matching
793 *
794 * input from FILE *, supports compressed input
795 * if @filename is " " then the standard input is used
796 *
797 * Returns an I/O context or NULL in case of error
798 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000799static void *
800xmlFileOpen_real (const char *filename) {
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800801 const char *path = filename;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000802 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000803
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000804 if (filename == NULL)
805 return(NULL);
806
Owen Taylor3473f882001-02-23 17:55:21 +0000807 if (!strcmp(filename, "-")) {
808 fd = stdin;
809 return((void *) fd);
810 }
811
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000812 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000813#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000814 path = &filename[17];
815#else
Owen Taylor3473f882001-02-23 17:55:21 +0000816 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000817#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000818 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000819#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000820 path = &filename[8];
821#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000822 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000823#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000824 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
825 /* lots of generators seems to lazy to read RFC 1738 */
826#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
827 path = &filename[6];
828#else
829 path = &filename[5];
830#endif
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800831 }
Owen Taylor3473f882001-02-23 17:55:21 +0000832
Stéphane Michaut454e3972017-08-28 14:30:43 +0200833 /* Do not check DDNAME on zOS ! */
834#if !defined(__MVS__)
Owen Taylor3473f882001-02-23 17:55:21 +0000835 if (!xmlCheckFilename(path))
836 return(NULL);
Stéphane Michaut454e3972017-08-28 14:30:43 +0200837#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000838
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000839#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Nick Wellnhofer56723972017-10-09 15:35:32 +0200840 fd = xmlWrapOpenUtf8(path, 0);
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000841#else
842 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000843#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000844 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000845 return((void *) fd);
846}
847
848/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000849 * xmlFileOpen:
850 * @filename: the URI for matching
851 *
852 * Wrapper around xmlFileOpen_real that try it with an unescaped
853 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000854 *
855 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000856 */
857void *
858xmlFileOpen (const char *filename) {
859 char *unescaped;
860 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000861
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000862 retval = xmlFileOpen_real(filename);
863 if (retval == NULL) {
864 unescaped = xmlURIUnescapeString(filename, 0, NULL);
865 if (unescaped != NULL) {
866 retval = xmlFileOpen_real(unescaped);
867 xmlFree(unescaped);
868 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000869 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000870
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000871 return retval;
872}
873
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000874#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000875/**
Owen Taylor3473f882001-02-23 17:55:21 +0000876 * xmlFileOpenW:
877 * @filename: the URI for matching
878 *
879 * output to from FILE *,
880 * if @filename is "-" then the standard output is used
881 *
882 * Returns an I/O context or NULL in case of error
883 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000884static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000885xmlFileOpenW (const char *filename) {
886 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000887 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000888
889 if (!strcmp(filename, "-")) {
890 fd = stdout;
891 return((void *) fd);
892 }
893
Daniel Veillardf4862f02002-09-10 11:13:43 +0000894 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000895#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000896 path = &filename[17];
897#else
Owen Taylor3473f882001-02-23 17:55:21 +0000898 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000899#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000900 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000901#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000902 path = &filename[8];
903#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000904 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000905#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200906 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000907 path = filename;
908
909 if (path == NULL)
910 return(NULL);
911
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000912#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Nick Wellnhofer56723972017-10-09 15:35:32 +0200913 fd = xmlWrapOpenUtf8(path, 1);
Stéphane Michaut454e3972017-08-28 14:30:43 +0200914#elif(__MVS__)
915 fd = fopen(path, "w");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000916#else
Stéphane Michaut454e3972017-08-28 14:30:43 +0200917 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000918#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000919
Stéphane Michaut454e3972017-08-28 14:30:43 +0200920 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000921 return((void *) fd);
922}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000923#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000924
925/**
926 * xmlFileRead:
927 * @context: the I/O context
928 * @buffer: where to drop data
929 * @len: number of bytes to write
930 *
931 * Read @len bytes to @buffer from the I/O channel.
932 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000933 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000934 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000935int
Owen Taylor3473f882001-02-23 17:55:21 +0000936xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000937 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200938 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +0000939 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000940 ret = fread(&buffer[0], 1, len, (FILE *) context);
941 if (ret < 0) xmlIOErr(0, "fread()");
942 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000943}
944
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000945#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000946/**
947 * xmlFileWrite:
948 * @context: the I/O context
949 * @buffer: where to drop data
950 * @len: number of bytes to write
951 *
952 * Write @len bytes from @buffer to the I/O channel.
953 *
954 * Returns the number of bytes written
955 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000956static int
Owen Taylor3473f882001-02-23 17:55:21 +0000957xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000958 int items;
959
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200960 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +0000961 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000962 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000963 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000964 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000965 return(-1);
966 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000967 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000968}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000969#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000970
971/**
972 * xmlFileClose:
973 * @context: the I/O context
974 *
975 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000976 *
977 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000978 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000979int
Owen Taylor3473f882001-02-23 17:55:21 +0000980xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000981 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000982 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000983
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000984 if (context == NULL)
985 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000986 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000987 if ((fil == stdout) || (fil == stderr)) {
988 ret = fflush(fil);
989 if (ret < 0)
990 xmlIOErr(0, "fflush()");
991 return(0);
992 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000993 if (fil == stdin)
994 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000995 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
996 if (ret < 0)
997 xmlIOErr(0, "fclose()");
998 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000999}
1000
1001/**
1002 * xmlFileFlush:
1003 * @context: the I/O context
1004 *
1005 * Flush an I/O channel
1006 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001007static int
Owen Taylor3473f882001-02-23 17:55:21 +00001008xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001009 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001010
1011 if (context == NULL)
1012 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001013 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1014 if (ret < 0)
1015 xmlIOErr(0, "fflush()");
1016 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001017}
1018
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001019#ifdef LIBXML_OUTPUT_ENABLED
1020/**
1021 * xmlBufferWrite:
1022 * @context: the xmlBuffer
1023 * @buffer: the data to write
1024 * @len: number of bytes to write
1025 *
1026 * Write @len bytes from @buffer to the xml buffer
1027 *
1028 * Returns the number of bytes written
1029 */
1030static int
1031xmlBufferWrite (void * context, const char * buffer, int len) {
1032 int ret;
1033
1034 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1035 if (ret != 0)
1036 return(-1);
1037 return(len);
1038}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001039#endif
1040
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001041#ifdef LIBXML_ZLIB_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001042/************************************************************************
1043 * *
1044 * I/O for compressed file accesses *
1045 * *
1046 ************************************************************************/
1047/**
1048 * xmlGzfileMatch:
1049 * @filename: the URI for matching
1050 *
1051 * input from compressed file test
1052 *
1053 * Returns 1 if matches, 0 otherwise
1054 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001055static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001056xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001057 return(1);
1058}
1059
1060/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001061 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001062 * @filename: the URI for matching
1063 *
1064 * input from compressed file open
1065 * if @filename is " " then the standard input is used
1066 *
1067 * Returns an I/O context or NULL in case of error
1068 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001069static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001070xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001071 const char *path = NULL;
1072 gzFile fd;
1073
1074 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001075 int duped_fd = dup(fileno(stdin));
1076 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001077 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001078 close(duped_fd); /* gzdOpen() does not close on failure */
1079 }
1080
Owen Taylor3473f882001-02-23 17:55:21 +00001081 return((void *) fd);
1082 }
1083
Daniel Veillardf4862f02002-09-10 11:13:43 +00001084 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001085#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001086 path = &filename[17];
1087#else
Owen Taylor3473f882001-02-23 17:55:21 +00001088 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001089#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001090 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001091#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001092 path = &filename[8];
1093#else
Owen Taylor3473f882001-02-23 17:55:21 +00001094 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001095#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001096 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001097 path = filename;
1098
1099 if (path == NULL)
1100 return(NULL);
1101 if (!xmlCheckFilename(path))
1102 return(NULL);
1103
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001104#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Nick Wellnhofer56723972017-10-09 15:35:32 +02001105 fd = xmlWrapGzOpenUtf8(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001106#else
Owen Taylor3473f882001-02-23 17:55:21 +00001107 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001108#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001109 return((void *) fd);
1110}
1111
1112/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001113 * xmlGzfileOpen:
1114 * @filename: the URI for matching
1115 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001116 * Wrapper around xmlGzfileOpen if the open fais, it will
1117 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001118 */
1119static void *
1120xmlGzfileOpen (const char *filename) {
1121 char *unescaped;
1122 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001123
1124 retval = xmlGzfileOpen_real(filename);
1125 if (retval == NULL) {
1126 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1127 if (unescaped != NULL) {
1128 retval = xmlGzfileOpen_real(unescaped);
1129 }
1130 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001131 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001132 return retval;
1133}
1134
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001135#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001136/**
Owen Taylor3473f882001-02-23 17:55:21 +00001137 * xmlGzfileOpenW:
1138 * @filename: the URI for matching
1139 * @compression: the compression factor (0 - 9 included)
1140 *
1141 * input from compressed file open
1142 * if @filename is " " then the standard input is used
1143 *
1144 * Returns an I/O context or NULL in case of error
1145 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001146static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001147xmlGzfileOpenW (const char *filename, int compression) {
1148 const char *path = NULL;
1149 char mode[15];
1150 gzFile fd;
1151
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001152 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001153 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001154 int duped_fd = dup(fileno(stdout));
1155 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001156 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001157 close(duped_fd); /* gzdOpen() does not close on failure */
1158 }
1159
Owen Taylor3473f882001-02-23 17:55:21 +00001160 return((void *) fd);
1161 }
1162
Daniel Veillardf4862f02002-09-10 11:13:43 +00001163 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001164#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001165 path = &filename[17];
1166#else
Owen Taylor3473f882001-02-23 17:55:21 +00001167 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001168#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001169 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001170#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001171 path = &filename[8];
1172#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001173 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001174#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001175 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001176 path = filename;
1177
1178 if (path == NULL)
1179 return(NULL);
1180
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001181#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Nick Wellnhofer56723972017-10-09 15:35:32 +02001182 fd = xmlWrapGzOpenUtf8(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001183#else
Owen Taylor3473f882001-02-23 17:55:21 +00001184 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001185#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001186 return((void *) fd);
1187}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001188#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001189
1190/**
1191 * xmlGzfileRead:
1192 * @context: the I/O context
1193 * @buffer: where to drop data
1194 * @len: number of bytes to write
1195 *
1196 * Read @len bytes to @buffer from the compressed I/O channel.
1197 *
Nick Wellnhofer5a0ae662017-06-17 23:20:38 +02001198 * Returns the number of bytes read.
Owen Taylor3473f882001-02-23 17:55:21 +00001199 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001200static int
Owen Taylor3473f882001-02-23 17:55:21 +00001201xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001202 int ret;
1203
1204 ret = gzread((gzFile) context, &buffer[0], len);
1205 if (ret < 0) xmlIOErr(0, "gzread()");
1206 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001207}
1208
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001209#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001210/**
1211 * xmlGzfileWrite:
1212 * @context: the I/O context
1213 * @buffer: where to drop data
1214 * @len: number of bytes to write
1215 *
1216 * Write @len bytes from @buffer to the compressed I/O channel.
1217 *
1218 * Returns the number of bytes written
1219 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001220static int
Owen Taylor3473f882001-02-23 17:55:21 +00001221xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001222 int ret;
1223
1224 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1225 if (ret < 0) xmlIOErr(0, "gzwrite()");
1226 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001227}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001228#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001229
1230/**
1231 * xmlGzfileClose:
1232 * @context: the I/O context
1233 *
1234 * Close a compressed I/O channel
1235 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001236static int
Owen Taylor3473f882001-02-23 17:55:21 +00001237xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001238 int ret;
1239
1240 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1241 if (ret < 0) xmlIOErr(0, "gzclose()");
1242 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001243}
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001244#endif /* LIBXML_ZLIB_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001245
Daniel Veillard18b89882015-11-03 15:46:29 +08001246#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001247/************************************************************************
1248 * *
1249 * I/O for compressed file accesses *
1250 * *
1251 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001252#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001253/**
1254 * xmlXzfileMatch:
1255 * @filename: the URI for matching
1256 *
1257 * input from compressed file test
1258 *
1259 * Returns 1 if matches, 0 otherwise
1260 */
1261static int
1262xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1263 return(1);
1264}
1265
1266/**
1267 * xmlXzFileOpen_real:
1268 * @filename: the URI for matching
1269 *
1270 * input from compressed file open
1271 * if @filename is " " then the standard input is used
1272 *
1273 * Returns an I/O context or NULL in case of error
1274 */
1275static void *
1276xmlXzfileOpen_real (const char *filename) {
1277 const char *path = NULL;
1278 xzFile fd;
1279
1280 if (!strcmp(filename, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001281 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001282 return((void *) fd);
1283 }
1284
1285 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1286 path = &filename[16];
1287 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1288 path = &filename[7];
1289 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1290 /* lots of generators seems to lazy to read RFC 1738 */
1291 path = &filename[5];
1292 } else
1293 path = filename;
1294
1295 if (path == NULL)
1296 return(NULL);
1297 if (!xmlCheckFilename(path))
1298 return(NULL);
1299
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001300 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001301 return((void *) fd);
1302}
1303
1304/**
1305 * xmlXzfileOpen:
1306 * @filename: the URI for matching
1307 *
1308 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1309 * version of @filename, if this fails fallback to @filename
1310 *
1311 * Returns a handler or NULL in case or failure
1312 */
1313static void *
1314xmlXzfileOpen (const char *filename) {
1315 char *unescaped;
1316 void *retval;
1317
1318 retval = xmlXzfileOpen_real(filename);
1319 if (retval == NULL) {
1320 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1321 if (unescaped != NULL) {
1322 retval = xmlXzfileOpen_real(unescaped);
1323 }
1324 xmlFree(unescaped);
1325 }
1326
1327 return retval;
1328}
1329
1330/**
1331 * xmlXzfileRead:
1332 * @context: the I/O context
1333 * @buffer: where to drop data
1334 * @len: number of bytes to write
1335 *
1336 * Read @len bytes to @buffer from the compressed I/O channel.
1337 *
1338 * Returns the number of bytes written
1339 */
1340static int
1341xmlXzfileRead (void * context, char * buffer, int len) {
1342 int ret;
1343
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001344 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001345 if (ret < 0) xmlIOErr(0, "xzread()");
1346 return(ret);
1347}
1348
1349/**
1350 * xmlXzfileClose:
1351 * @context: the I/O context
1352 *
1353 * Close a compressed I/O channel
1354 */
1355static int
1356xmlXzfileClose (void * context) {
1357 int ret;
1358
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001359 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001360 if (ret < 0) xmlIOErr(0, "xzclose()");
1361 return(ret);
1362}
Daniel Veillard18b89882015-11-03 15:46:29 +08001363#endif /* LIBXML_LZMA_ENABLED */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001364
Owen Taylor3473f882001-02-23 17:55:21 +00001365#ifdef LIBXML_HTTP_ENABLED
1366/************************************************************************
1367 * *
1368 * I/O for HTTP file accesses *
1369 * *
1370 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001371
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001372#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001373typedef struct xmlIOHTTPWriteCtxt_
1374{
1375 int compression;
1376
1377 char * uri;
1378
1379 void * doc_buff;
1380
1381} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1382
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001383#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001384
1385#define DFLT_WBITS ( -15 )
1386#define DFLT_MEM_LVL ( 8 )
1387#define GZ_MAGIC1 ( 0x1f )
1388#define GZ_MAGIC2 ( 0x8b )
1389#define LXML_ZLIB_OS_CODE ( 0x03 )
1390#define INIT_HTTP_BUFF_SIZE ( 32768 )
1391#define DFLT_ZLIB_RATIO ( 5 )
1392
1393/*
1394** Data structure and functions to work with sending compressed data
1395** via HTTP.
1396*/
1397
1398typedef struct xmlZMemBuff_
1399{
1400 unsigned long size;
1401 unsigned long crc;
1402
1403 unsigned char * zbuff;
1404 z_stream zctrl;
1405
1406} xmlZMemBuff, *xmlZMemBuffPtr;
1407
1408/**
1409 * append_reverse_ulong
1410 * @buff: Compressed memory buffer
1411 * @data: Unsigned long to append
1412 *
1413 * Append a unsigned long in reverse byte order to the end of the
1414 * memory buffer.
1415 */
1416static void
1417append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1418
1419 int idx;
1420
1421 if ( buff == NULL )
1422 return;
1423
1424 /*
1425 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001426 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001427 ** support 64 bit file sizes, this code would need to be patched
1428 ** as well.
1429 */
1430
1431 for ( idx = 0; idx < 4; idx++ ) {
1432 *buff->zctrl.next_out = ( data & 0xff );
1433 data >>= 8;
1434 buff->zctrl.next_out++;
1435 }
1436
1437 return;
1438}
1439
1440/**
1441 *
1442 * xmlFreeZMemBuff
1443 * @buff: The memory buffer context to clear
1444 *
1445 * Release all the resources associated with the compressed memory buffer.
1446 */
1447static void
1448xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001449
1450#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001451 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001452#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001453
1454 if ( buff == NULL )
1455 return;
1456
1457 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001458#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001459 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001460 if ( z_err != Z_OK )
1461 xmlGenericError( xmlGenericErrorContext,
1462 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1463 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001464#else
1465 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001466#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001467
1468 xmlFree( buff );
1469 return;
1470}
1471
1472/**
1473 * xmlCreateZMemBuff
1474 *@compression: Compression value to use
1475 *
1476 * Create a memory buffer to hold the compressed XML document. The
1477 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001478 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001479 * write the document to disk. The code for the header/trailer data to
1480 * the compression is plagiarized from the zlib source files.
1481 */
1482static void *
1483xmlCreateZMemBuff( int compression ) {
1484
1485 int z_err;
1486 int hdr_lgth;
1487 xmlZMemBuffPtr buff = NULL;
1488
1489 if ( ( compression < 1 ) || ( compression > 9 ) )
1490 return ( NULL );
1491
1492 /* Create the control and data areas */
1493
1494 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1495 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001496 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001497 return ( NULL );
1498 }
1499
1500 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1501 buff->size = INIT_HTTP_BUFF_SIZE;
1502 buff->zbuff = xmlMalloc( buff->size );
1503 if ( buff->zbuff == NULL ) {
1504 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001505 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001506 return ( NULL );
1507 }
1508
1509 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1510 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1511 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001512 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001513 xmlFreeZMemBuff( buff );
1514 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001515 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001516 "xmlCreateZMemBuff: %s %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001517 "Error initializing compression context. ZLIB error:",
1518 z_err );
1519 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001520 return ( NULL );
1521 }
1522
1523 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001524 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001525 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1526 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001527 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001528 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1529 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1530 buff->zctrl.avail_out = buff->size - hdr_lgth;
1531
1532 return ( buff );
1533}
1534
1535/**
1536 * xmlZMemBuffExtend
1537 * @buff: Buffer used to compress and consolidate data.
1538 * @ext_amt: Number of bytes to extend the buffer.
1539 *
1540 * Extend the internal buffer used to store the compressed data by the
1541 * specified amount.
1542 *
1543 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1544 * the original buffer still exists at the original size.
1545 */
1546static int
1547xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1548
1549 int rc = -1;
1550 size_t new_size;
1551 size_t cur_used;
1552
1553 unsigned char * tmp_ptr = NULL;
1554
1555 if ( buff == NULL )
1556 return ( -1 );
1557
1558 else if ( ext_amt == 0 )
1559 return ( 0 );
1560
1561 cur_used = buff->zctrl.next_out - buff->zbuff;
1562 new_size = buff->size + ext_amt;
1563
1564#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001565 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001566 xmlGenericError( xmlGenericErrorContext,
1567 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1568 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001569 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001570 (cur_used - new_size ) );
1571#endif
1572
1573 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1574 if ( tmp_ptr != NULL ) {
1575 rc = 0;
1576 buff->size = new_size;
1577 buff->zbuff = tmp_ptr;
1578 buff->zctrl.next_out = tmp_ptr + cur_used;
1579 buff->zctrl.avail_out = new_size - cur_used;
1580 }
1581 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001582 xmlChar msg[500];
1583 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001584 "xmlZMemBuffExtend: %s %lu bytes.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001585 "Allocation failure extending output buffer to",
Nick Wellnhoferc2545cb2016-08-22 11:44:18 +02001586 (unsigned long) new_size );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001587 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001588 }
1589
1590 return ( rc );
1591}
1592
1593/**
1594 * xmlZMemBuffAppend
1595 * @buff: Buffer used to compress and consolidate data
1596 * @src: Uncompressed source content to append to buffer
1597 * @len: Length of source data to append to buffer
1598 *
1599 * Compress and append data to the internal buffer. The data buffer
1600 * will be expanded if needed to store the additional data.
1601 *
1602 * Returns the number of bytes appended to the buffer or -1 on error.
1603 */
1604static int
1605xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1606
1607 int z_err;
1608 size_t min_accept;
1609
1610 if ( ( buff == NULL ) || ( src == NULL ) )
1611 return ( -1 );
1612
1613 buff->zctrl.avail_in = len;
1614 buff->zctrl.next_in = (unsigned char *)src;
1615 while ( buff->zctrl.avail_in > 0 ) {
1616 /*
1617 ** Extend the buffer prior to deflate call if a reasonable amount
1618 ** of output buffer space is not available.
1619 */
1620 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1621 if ( buff->zctrl.avail_out <= min_accept ) {
1622 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1623 return ( -1 );
1624 }
1625
1626 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1627 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001628 xmlChar msg[500];
1629 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001630 "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001631 "Compression error while appending",
1632 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001633 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001634 return ( -1 );
1635 }
1636 }
1637
1638 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1639
1640 return ( len );
1641}
1642
1643/**
1644 * xmlZMemBuffGetContent
1645 * @buff: Compressed memory content buffer
1646 * @data_ref: Pointer reference to point to compressed content
1647 *
1648 * Flushes the compression buffers, appends gzip file trailers and
1649 * returns the compressed content and length of the compressed data.
1650 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1651 *
1652 * Returns the length of the compressed data or -1 on error.
1653 */
1654static int
1655xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1656
1657 int zlgth = -1;
1658 int z_err;
1659
1660 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1661 return ( -1 );
1662
1663 /* Need to loop until compression output buffers are flushed */
1664
1665 do
1666 {
1667 z_err = deflate( &buff->zctrl, Z_FINISH );
1668 if ( z_err == Z_OK ) {
1669 /* In this case Z_OK means more buffer space needed */
1670
1671 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1672 return ( -1 );
1673 }
1674 }
1675 while ( z_err == Z_OK );
1676
1677 /* If the compression state is not Z_STREAM_END, some error occurred */
1678
1679 if ( z_err == Z_STREAM_END ) {
1680
1681 /* Need to append the gzip data trailer */
1682
1683 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1684 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1685 return ( -1 );
1686 }
1687
1688 /*
1689 ** For whatever reason, the CRC and length data are pushed out
1690 ** in reverse byte order. So a memcpy can't be used here.
1691 */
1692
1693 append_reverse_ulong( buff, buff->crc );
1694 append_reverse_ulong( buff, buff->zctrl.total_in );
1695
1696 zlgth = buff->zctrl.next_out - buff->zbuff;
1697 *data_ref = (char *)buff->zbuff;
1698 }
1699
Daniel Veillard05d987b2003-10-08 11:54:57 +00001700 else {
1701 xmlChar msg[500];
1702 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001703 "xmlZMemBuffGetContent: %s - %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001704 "Error flushing zlib buffers. Error code", z_err );
1705 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1706 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001707
Daniel Veillardf012a642001-07-23 19:10:52 +00001708 return ( zlgth );
1709}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001710#endif /* LIBXML_OUTPUT_ENABLED */
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001711#endif /* LIBXML_ZLIB_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001712
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001713#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001714/**
1715 * xmlFreeHTTPWriteCtxt
1716 * @ctxt: Context to cleanup
1717 *
1718 * Free allocated memory and reclaim system resources.
1719 *
1720 * No return value.
1721 */
1722static void
1723xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1724{
1725 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001726 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001727
1728 if ( ctxt->doc_buff != NULL ) {
1729
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001730#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001731 if ( ctxt->compression > 0 ) {
1732 xmlFreeZMemBuff( ctxt->doc_buff );
1733 }
1734 else
1735#endif
1736 {
1737 xmlOutputBufferClose( ctxt->doc_buff );
1738 }
1739 }
1740
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001741 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001742 return;
1743}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001744#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001745
1746
Owen Taylor3473f882001-02-23 17:55:21 +00001747/**
1748 * xmlIOHTTPMatch:
1749 * @filename: the URI for matching
1750 *
1751 * check if the URI matches an HTTP one
1752 *
1753 * Returns 1 if matches, 0 otherwise
1754 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001755int
Owen Taylor3473f882001-02-23 17:55:21 +00001756xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001757 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001758 return(1);
1759 return(0);
1760}
1761
1762/**
1763 * xmlIOHTTPOpen:
1764 * @filename: the URI for matching
1765 *
1766 * open an HTTP I/O channel
1767 *
1768 * Returns an I/O context or NULL in case of error
1769 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001770void *
Owen Taylor3473f882001-02-23 17:55:21 +00001771xmlIOHTTPOpen (const char *filename) {
1772 return(xmlNanoHTTPOpen(filename, NULL));
1773}
1774
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001775#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001776/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001777 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001778 * @post_uri: The destination URI for the document
1779 * @compression: The compression desired for the document.
1780 *
1781 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1782 * request. Non-static as is called from the output buffer creation routine.
1783 *
1784 * Returns an I/O context or NULL in case of error.
1785 */
1786
1787void *
Nick Wellnhofer81c01ee2017-06-17 14:12:53 +02001788xmlIOHTTPOpenW(const char *post_uri, int compression ATTRIBUTE_UNUSED)
Daniel Veillard572577e2002-01-18 16:23:55 +00001789{
Daniel Veillardf012a642001-07-23 19:10:52 +00001790
Daniel Veillard572577e2002-01-18 16:23:55 +00001791 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001792
Daniel Veillard572577e2002-01-18 16:23:55 +00001793 if (post_uri == NULL)
1794 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001795
Daniel Veillard572577e2002-01-18 16:23:55 +00001796 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1797 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001798 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001799 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001800 }
1801
Daniel Veillard572577e2002-01-18 16:23:55 +00001802 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001803
Daniel Veillard572577e2002-01-18 16:23:55 +00001804 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1805 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001806 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001807 xmlFreeHTTPWriteCtxt(ctxt);
1808 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001809 }
1810
1811 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001812 * ** Since the document length is required for an HTTP post,
1813 * ** need to put the document into a buffer. A memory buffer
1814 * ** is being used to avoid pushing the data to disk and back.
1815 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001816
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001817#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard572577e2002-01-18 16:23:55 +00001818 if ((compression > 0) && (compression <= 9)) {
1819
1820 ctxt->compression = compression;
1821 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1822 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001823#endif
1824 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001825 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001826
Daniel Veillardda3fee42008-09-01 13:08:57 +00001827 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001828 }
1829
Daniel Veillard572577e2002-01-18 16:23:55 +00001830 if (ctxt->doc_buff == NULL) {
1831 xmlFreeHTTPWriteCtxt(ctxt);
1832 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001833 }
1834
Daniel Veillard572577e2002-01-18 16:23:55 +00001835 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001836}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001837#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001838
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001839#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001840/**
1841 * xmlIOHTTPDfltOpenW
1842 * @post_uri: The destination URI for this document.
1843 *
1844 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1845 * HTTP post command. This function should generally not be used as
1846 * the open callback is short circuited in xmlOutputBufferCreateFile.
1847 *
1848 * Returns a pointer to the new IO context.
1849 */
1850static void *
1851xmlIOHTTPDfltOpenW( const char * post_uri ) {
1852 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1853}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001854#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001855
1856/**
Owen Taylor3473f882001-02-23 17:55:21 +00001857 * xmlIOHTTPRead:
1858 * @context: the I/O context
1859 * @buffer: where to drop data
1860 * @len: number of bytes to write
1861 *
1862 * Read @len bytes to @buffer from the I/O channel.
1863 *
1864 * Returns the number of bytes written
1865 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001866int
Owen Taylor3473f882001-02-23 17:55:21 +00001867xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001868 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001869 return(xmlNanoHTTPRead(context, &buffer[0], len));
1870}
1871
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001872#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001873/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001874 * xmlIOHTTPWrite
1875 * @context: previously opened writing context
1876 * @buffer: data to output to temporary buffer
1877 * @len: bytes to output
1878 *
1879 * Collect data from memory buffer into a temporary file for later
1880 * processing.
1881 *
1882 * Returns number of bytes written.
1883 */
1884
1885static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001886xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001887
1888 xmlIOHTTPWriteCtxtPtr ctxt = context;
1889
1890 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1891 return ( -1 );
1892
1893 if ( len > 0 ) {
1894
1895 /* Use gzwrite or fwrite as previously setup in the open call */
1896
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001897#ifdef LIBXML_ZLIB_ENABLED
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001898 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001899 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1900
1901 else
1902#endif
1903 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1904
1905 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001906 xmlChar msg[500];
1907 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001908 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001909 "Error appending to internal buffer.",
1910 "Error sending document to URI",
1911 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001912 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001913 }
1914 }
1915
1916 return ( len );
1917}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001918#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001919
1920
1921/**
Owen Taylor3473f882001-02-23 17:55:21 +00001922 * xmlIOHTTPClose:
1923 * @context: the I/O context
1924 *
1925 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001926 *
1927 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001928 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001929int
Owen Taylor3473f882001-02-23 17:55:21 +00001930xmlIOHTTPClose (void * context) {
1931 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001932 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001933}
Daniel Veillardf012a642001-07-23 19:10:52 +00001934
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001935#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001936/**
1937 * xmlIOHTTCloseWrite
1938 * @context: The I/O context
1939 * @http_mthd: The HTTP method to be used when sending the data
1940 *
1941 * Close the transmit HTTP I/O channel and actually send the data.
1942 */
1943static int
1944xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1945
1946 int close_rc = -1;
1947 int http_rtn = 0;
1948 int content_lgth = 0;
1949 xmlIOHTTPWriteCtxtPtr ctxt = context;
1950
1951 char * http_content = NULL;
1952 char * content_encoding = NULL;
1953 char * content_type = (char *) "text/xml";
1954 void * http_ctxt = NULL;
1955
1956 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1957 return ( -1 );
1958
1959 /* Retrieve the content from the appropriate buffer */
1960
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001961#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001962
1963 if ( ctxt->compression > 0 ) {
1964 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1965 content_encoding = (char *) "Content-Encoding: gzip";
1966 }
1967 else
1968#endif
1969 {
1970 /* Pull the data out of the memory output buffer */
1971
1972 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08001973 http_content = (char *) xmlBufContent(dctxt->buffer);
1974 content_lgth = xmlBufUse(dctxt->buffer);
Daniel Veillardf012a642001-07-23 19:10:52 +00001975 }
1976
1977 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001978 xmlChar msg[500];
1979 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001980 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001981 "Error retrieving content.\nUnable to",
1982 http_mthd, "data to URI", ctxt->uri );
1983 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001984 }
1985
1986 else {
1987
1988 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001989 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00001990 content_lgth );
1991
1992 if ( http_ctxt != NULL ) {
1993#ifdef DEBUG_HTTP
1994 /* If testing/debugging - dump reply with request content */
1995
1996 FILE * tst_file = NULL;
1997 char buffer[ 4096 ];
1998 char * dump_name = NULL;
1999 int avail;
2000
2001 xmlGenericError( xmlGenericErrorContext,
2002 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2003 http_mthd, ctxt->uri,
2004 xmlNanoHTTPReturnCode( http_ctxt ) );
2005
2006 /*
2007 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002008 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002009 ** standard error context.
2010 */
2011
2012 dump_name = tempnam( NULL, "lxml" );
2013 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002014 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002015
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002016 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002017 if ( tst_file != NULL ) {
2018 xmlGenericError( xmlGenericErrorContext,
2019 "Transmitted content saved in file: %s\n", buffer );
2020
2021 fwrite( http_content, sizeof( char ),
2022 content_lgth, tst_file );
2023 fclose( tst_file );
2024 }
2025
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002026 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002027 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002028 if ( tst_file != NULL ) {
2029 xmlGenericError( xmlGenericErrorContext,
2030 "Reply content saved in file: %s\n", buffer );
2031
2032
2033 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2034 buffer, sizeof( buffer ) )) > 0 ) {
2035
2036 fwrite( buffer, sizeof( char ), avail, tst_file );
2037 }
2038
2039 fclose( tst_file );
2040 }
2041
2042 free( dump_name );
2043 }
2044#endif /* DEBUG_HTTP */
2045
2046 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2047 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2048 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002049 else {
2050 xmlChar msg[500];
2051 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08002052 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002053 http_mthd, content_lgth,
2054 "bytes to URI", ctxt->uri,
2055 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002056 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2057 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002058
2059 xmlNanoHTTPClose( http_ctxt );
2060 xmlFree( content_type );
2061 }
2062 }
2063
2064 /* Final cleanups */
2065
2066 xmlFreeHTTPWriteCtxt( ctxt );
2067
2068 return ( close_rc );
2069}
2070
2071/**
2072 * xmlIOHTTPClosePut
2073 *
2074 * @context: The I/O context
2075 *
2076 * Close the transmit HTTP I/O channel and actually send data using a PUT
2077 * HTTP method.
2078 */
2079static int
2080xmlIOHTTPClosePut( void * ctxt ) {
2081 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2082}
2083
2084
2085/**
2086 * xmlIOHTTPClosePost
2087 *
2088 * @context: The I/O context
2089 *
2090 * Close the transmit HTTP I/O channel and actually send data using a POST
2091 * HTTP method.
2092 */
2093static int
2094xmlIOHTTPClosePost( void * ctxt ) {
2095 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2096}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002097#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002098
Owen Taylor3473f882001-02-23 17:55:21 +00002099#endif /* LIBXML_HTTP_ENABLED */
2100
2101#ifdef LIBXML_FTP_ENABLED
2102/************************************************************************
2103 * *
2104 * I/O for FTP file accesses *
2105 * *
2106 ************************************************************************/
2107/**
2108 * xmlIOFTPMatch:
2109 * @filename: the URI for matching
2110 *
2111 * check if the URI matches an FTP one
2112 *
2113 * Returns 1 if matches, 0 otherwise
2114 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002115int
Owen Taylor3473f882001-02-23 17:55:21 +00002116xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002117 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002118 return(1);
2119 return(0);
2120}
2121
2122/**
2123 * xmlIOFTPOpen:
2124 * @filename: the URI for matching
2125 *
2126 * open an FTP I/O channel
2127 *
2128 * Returns an I/O context or NULL in case of error
2129 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002130void *
Owen Taylor3473f882001-02-23 17:55:21 +00002131xmlIOFTPOpen (const char *filename) {
2132 return(xmlNanoFTPOpen(filename));
2133}
2134
2135/**
2136 * xmlIOFTPRead:
2137 * @context: the I/O context
2138 * @buffer: where to drop data
2139 * @len: number of bytes to write
2140 *
2141 * Read @len bytes to @buffer from the I/O channel.
2142 *
2143 * Returns the number of bytes written
2144 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002145int
Owen Taylor3473f882001-02-23 17:55:21 +00002146xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002147 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002148 return(xmlNanoFTPRead(context, &buffer[0], len));
2149}
2150
2151/**
2152 * xmlIOFTPClose:
2153 * @context: the I/O context
2154 *
2155 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002156 *
2157 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002158 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002159int
Owen Taylor3473f882001-02-23 17:55:21 +00002160xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002161 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002162}
2163#endif /* LIBXML_FTP_ENABLED */
2164
2165
2166/**
2167 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002168 * @matchFunc: the xmlInputMatchCallback
2169 * @openFunc: the xmlInputOpenCallback
2170 * @readFunc: the xmlInputReadCallback
2171 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002172 *
2173 * Register a new set of I/O callback for handling parser input.
2174 *
2175 * Returns the registered handler number or -1 in case of error
2176 */
2177int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002178xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2179 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2180 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002181 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2182 return(-1);
2183 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002184 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2185 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2186 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2187 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002188 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002189 return(xmlInputCallbackNr++);
2190}
2191
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002192#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002193/**
2194 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002195 * @matchFunc: the xmlOutputMatchCallback
2196 * @openFunc: the xmlOutputOpenCallback
2197 * @writeFunc: the xmlOutputWriteCallback
2198 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002199 *
2200 * Register a new set of I/O callback for handling output.
2201 *
2202 * Returns the registered handler number or -1 in case of error
2203 */
2204int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002205xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2206 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2207 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002208 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002209 return(-1);
2210 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002211 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2212 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2213 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2214 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002215 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002216 return(xmlOutputCallbackNr++);
2217}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002218#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002219
2220/**
2221 * xmlRegisterDefaultInputCallbacks:
2222 *
2223 * Registers the default compiled-in I/O handlers.
2224 */
2225void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002226xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002227 if (xmlInputCallbackInitialized)
2228 return;
2229
2230 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2231 xmlFileRead, xmlFileClose);
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002232#ifdef LIBXML_ZLIB_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002233 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2234 xmlGzfileRead, xmlGzfileClose);
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002235#endif /* LIBXML_ZLIB_ENABLED */
Daniel Veillard18b89882015-11-03 15:46:29 +08002236#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002237 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2238 xmlXzfileRead, xmlXzfileClose);
Daniel Veillard18b89882015-11-03 15:46:29 +08002239#endif /* LIBXML_LZMA_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002240
2241#ifdef LIBXML_HTTP_ENABLED
2242 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2243 xmlIOHTTPRead, xmlIOHTTPClose);
2244#endif /* LIBXML_HTTP_ENABLED */
2245
2246#ifdef LIBXML_FTP_ENABLED
2247 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2248 xmlIOFTPRead, xmlIOFTPClose);
2249#endif /* LIBXML_FTP_ENABLED */
2250 xmlInputCallbackInitialized = 1;
2251}
2252
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002253#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002254/**
2255 * xmlRegisterDefaultOutputCallbacks:
2256 *
2257 * Registers the default compiled-in I/O handlers.
2258 */
2259void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002260xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002261 if (xmlOutputCallbackInitialized)
2262 return;
2263
2264 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2265 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002266
2267#ifdef LIBXML_HTTP_ENABLED
2268 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2269 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2270#endif
2271
Owen Taylor3473f882001-02-23 17:55:21 +00002272/*********************************
2273 No way a-priori to distinguish between gzipped files from
2274 uncompressed ones except opening if existing then closing
2275 and saving with same compression ratio ... a pain.
2276
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002277#ifdef LIBXML_ZLIB_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002278 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2279 xmlGzfileWrite, xmlGzfileClose);
2280#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002281
2282 Nor FTP PUT ....
2283#ifdef LIBXML_FTP_ENABLED
2284 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2285 xmlIOFTPWrite, xmlIOFTPClose);
2286#endif
2287 **********************************/
2288 xmlOutputCallbackInitialized = 1;
2289}
2290
Daniel Veillardf012a642001-07-23 19:10:52 +00002291#ifdef LIBXML_HTTP_ENABLED
2292/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002293 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002294 *
2295 * By default, libxml submits HTTP output requests using the "PUT" method.
2296 * Calling this method changes the HTTP output method to use the "POST"
2297 * method instead.
2298 *
2299 */
2300void
2301xmlRegisterHTTPPostCallbacks( void ) {
2302
2303 /* Register defaults if not done previously */
2304
2305 if ( xmlOutputCallbackInitialized == 0 )
2306 xmlRegisterDefaultOutputCallbacks( );
2307
2308 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2309 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2310 return;
2311}
2312#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002313#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002314
Owen Taylor3473f882001-02-23 17:55:21 +00002315/**
2316 * xmlAllocParserInputBuffer:
2317 * @enc: the charset encoding if known
2318 *
2319 * Create a buffered parser input for progressive parsing
2320 *
2321 * Returns the new parser input or NULL
2322 */
2323xmlParserInputBufferPtr
2324xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2325 xmlParserInputBufferPtr ret;
2326
2327 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2328 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002329 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002330 return(NULL);
2331 }
2332 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002333 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002334 if (ret->buffer == NULL) {
2335 xmlFree(ret);
2336 return(NULL);
2337 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002338 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Owen Taylor3473f882001-02-23 17:55:21 +00002339 ret->encoder = xmlGetCharEncodingHandler(enc);
2340 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002341 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002342 else
2343 ret->raw = NULL;
2344 ret->readcallback = NULL;
2345 ret->closecallback = NULL;
2346 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002347 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002348 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002349
2350 return(ret);
2351}
2352
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002353#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002354/**
2355 * xmlAllocOutputBuffer:
2356 * @encoder: the encoding converter or NULL
2357 *
2358 * Create a buffered parser output
2359 *
2360 * Returns the new parser output or NULL
2361 */
2362xmlOutputBufferPtr
2363xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2364 xmlOutputBufferPtr ret;
2365
2366 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2367 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002368 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002369 return(NULL);
2370 }
2371 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002372 ret->buffer = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00002373 if (ret->buffer == NULL) {
2374 xmlFree(ret);
2375 return(NULL);
2376 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002377
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002378 /* try to avoid a performance problem with Windows realloc() */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002379 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2380 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002381
Daniel Veillardda3fee42008-09-01 13:08:57 +00002382 ret->encoder = encoder;
2383 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002384 ret->conv = xmlBufCreateSize(4000);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002385 if (ret->conv == NULL) {
2386 xmlFree(ret);
2387 return(NULL);
2388 }
2389
2390 /*
2391 * This call is designed to initiate the encoder state
2392 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002393 xmlCharEncOutput(ret, 1);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002394 } else
2395 ret->conv = NULL;
2396 ret->writecallback = NULL;
2397 ret->closecallback = NULL;
2398 ret->context = NULL;
2399 ret->written = 0;
2400
2401 return(ret);
2402}
2403
2404/**
2405 * xmlAllocOutputBufferInternal:
2406 * @encoder: the encoding converter or NULL
2407 *
2408 * Create a buffered parser output
2409 *
2410 * Returns the new parser output or NULL
2411 */
2412xmlOutputBufferPtr
2413xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2414 xmlOutputBufferPtr ret;
2415
2416 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2417 if (ret == NULL) {
2418 xmlIOErrMemory("creating output buffer");
2419 return(NULL);
2420 }
2421 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002422 ret->buffer = xmlBufCreate();
Daniel Veillardda3fee42008-09-01 13:08:57 +00002423 if (ret->buffer == NULL) {
2424 xmlFree(ret);
2425 return(NULL);
2426 }
2427
2428
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002429 /*
2430 * For conversion buffers we use the special IO handling
2431 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002432 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002433
Owen Taylor3473f882001-02-23 17:55:21 +00002434 ret->encoder = encoder;
2435 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002436 ret->conv = xmlBufCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002437 if (ret->conv == NULL) {
2438 xmlFree(ret);
2439 return(NULL);
2440 }
2441
Owen Taylor3473f882001-02-23 17:55:21 +00002442 /*
2443 * This call is designed to initiate the encoder state
2444 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002445 xmlCharEncOutput(ret, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002446 } else
2447 ret->conv = NULL;
2448 ret->writecallback = NULL;
2449 ret->closecallback = NULL;
2450 ret->context = NULL;
2451 ret->written = 0;
2452
2453 return(ret);
2454}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002455
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002456#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002457
2458/**
2459 * xmlFreeParserInputBuffer:
2460 * @in: a buffered parser input
2461 *
2462 * Free up the memory used by a buffered parser input
2463 */
2464void
2465xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002466 if (in == NULL) return;
2467
Owen Taylor3473f882001-02-23 17:55:21 +00002468 if (in->raw) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002469 xmlBufFree(in->raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002470 in->raw = NULL;
2471 }
2472 if (in->encoder != NULL) {
2473 xmlCharEncCloseFunc(in->encoder);
2474 }
2475 if (in->closecallback != NULL) {
2476 in->closecallback(in->context);
2477 }
2478 if (in->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002479 xmlBufFree(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00002480 in->buffer = NULL;
2481 }
2482
Owen Taylor3473f882001-02-23 17:55:21 +00002483 xmlFree(in);
2484}
2485
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002486#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002487/**
2488 * xmlOutputBufferClose:
2489 * @out: a buffered output
2490 *
2491 * flushes and close the output I/O channel
2492 * and free up all the associated resources
2493 *
2494 * Returns the number of byte written or -1 in case of error.
2495 */
2496int
Daniel Veillard828ce832003-10-08 19:19:10 +00002497xmlOutputBufferClose(xmlOutputBufferPtr out)
2498{
Owen Taylor3473f882001-02-23 17:55:21 +00002499 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002500 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002501
2502 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002503 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002504 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002505 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002506 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002507 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002508 }
2509 written = out->written;
2510 if (out->conv) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002511 xmlBufFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002512 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002513 }
2514 if (out->encoder != NULL) {
2515 xmlCharEncCloseFunc(out->encoder);
2516 }
2517 if (out->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002518 xmlBufFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002519 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002520 }
2521
Daniel Veillard828ce832003-10-08 19:19:10 +00002522 if (out->error)
2523 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002524 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002525 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002526}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002527#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002528
Daniel Veillard1b243b42004-06-08 10:16:42 +00002529xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002530__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002531 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002532 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002533 void *context = NULL;
2534
2535 if (xmlInputCallbackInitialized == 0)
2536 xmlRegisterDefaultInputCallbacks();
2537
2538 if (URI == NULL) return(NULL);
2539
2540 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002541 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002542 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002543 */
2544 if (context == NULL) {
2545 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2546 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2547 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002548 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002549 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002550 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002551 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002552 }
Owen Taylor3473f882001-02-23 17:55:21 +00002553 }
2554 }
2555 if (context == NULL) {
2556 return(NULL);
2557 }
2558
2559 /*
2560 * Allocate the Input buffer front-end.
2561 */
2562 ret = xmlAllocParserInputBuffer(enc);
2563 if (ret != NULL) {
2564 ret->context = context;
2565 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2566 ret->closecallback = xmlInputCallbackTable[i].closecallback;
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002567#ifdef LIBXML_ZLIB_ENABLED
William M. Brackc5cbf992003-10-29 22:15:13 +00002568 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2569 (strcmp(URI, "-") != 0)) {
Mark Adlera7e79f22010-01-19 16:28:48 +01002570#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2571 ret->compressed = !gzdirect(context);
2572#else
William M. Brackc07329e2003-09-08 01:57:30 +00002573 if (((z_stream *)context)->avail_in > 4) {
2574 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002575 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002576 if (gzread(context, buff4, 4) == 4) {
2577 if (strncmp(buff4, cptr, 4) == 0)
2578 ret->compressed = 0;
2579 else
2580 ret->compressed = 1;
2581 gzrewind(context);
2582 }
2583 }
Mark Adlera7e79f22010-01-19 16:28:48 +01002584#endif
William M. Brackc07329e2003-09-08 01:57:30 +00002585 }
2586#endif
Daniel Veillard18b89882015-11-03 15:46:29 +08002587#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08002588 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2589 (strcmp(URI, "-") != 0)) {
2590 ret->compressed = __libxml2_xzcompressed(context);
2591 }
2592#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002593 }
William M. Brack42331a92004-07-29 07:07:16 +00002594 else
2595 xmlInputCallbackTable[i].closecallback (context);
2596
Owen Taylor3473f882001-02-23 17:55:21 +00002597 return(ret);
2598}
2599
2600/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002601 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002602 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002603 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002604 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002605 * Create a buffered parser input for the progressive parsing of a file
2606 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002607 * Automatic support for ZLIB/Compress compressed document is provided
2608 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002609 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002610 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002611 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002612 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002613xmlParserInputBufferPtr
2614xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2615 if ((xmlParserInputBufferCreateFilenameValue)) {
2616 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2617 }
2618 return __xmlParserInputBufferCreateFilename(URI, enc);
2619}
2620
2621#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002622xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002623__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002624 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002625 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002626 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002627 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002628 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002629 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002630 char *unescaped = NULL;
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002631#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard966a31e2004-05-09 02:58:44 +00002632 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002633#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002634
Owen Taylor3473f882001-02-23 17:55:21 +00002635 if (xmlOutputCallbackInitialized == 0)
2636 xmlRegisterDefaultOutputCallbacks();
2637
2638 if (URI == NULL) return(NULL);
2639
Daniel Veillard966a31e2004-05-09 02:58:44 +00002640 puri = xmlParseURI(URI);
2641 if (puri != NULL) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002642#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard18a65092004-05-11 15:57:42 +00002643 if ((puri->scheme != NULL) &&
2644 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002645 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002646#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002647 /*
2648 * try to limit the damages of the URI unescaping code.
2649 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002650 if ((puri->scheme == NULL) ||
2651 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002652 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2653 xmlFreeURI(puri);
2654 }
Owen Taylor3473f882001-02-23 17:55:21 +00002655
2656 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002657 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002658 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002659 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002660 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002661 if (unescaped != NULL) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002662#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard966a31e2004-05-09 02:58:44 +00002663 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002664 context = xmlGzfileOpenW(unescaped, compression);
2665 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002666 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002667 if (ret != NULL) {
2668 ret->context = context;
2669 ret->writecallback = xmlGzfileWrite;
2670 ret->closecallback = xmlGzfileClose;
2671 }
2672 xmlFree(unescaped);
2673 return(ret);
2674 }
2675 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002676#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002677 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2678 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2679 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002680#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002681 /* Need to pass compression parameter into HTTP open calls */
2682 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2683 context = xmlIOHTTPOpenW(unescaped, compression);
2684 else
2685#endif
2686 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2687 if (context != NULL)
2688 break;
2689 }
2690 }
2691 xmlFree(unescaped);
2692 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002693
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002694 /*
2695 * If this failed try with a non-escaped URI this may be a strange
2696 * filename
2697 */
2698 if (context == NULL) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002699#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard966a31e2004-05-09 02:58:44 +00002700 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002701 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002702 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002703 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002704 if (ret != NULL) {
2705 ret->context = context;
2706 ret->writecallback = xmlGzfileWrite;
2707 ret->closecallback = xmlGzfileClose;
2708 }
2709 return(ret);
2710 }
2711 }
2712#endif
2713 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2714 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002715 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002716#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002717 /* Need to pass compression parameter into HTTP open calls */
2718 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2719 context = xmlIOHTTPOpenW(URI, compression);
2720 else
2721#endif
2722 context = xmlOutputCallbackTable[i].opencallback(URI);
2723 if (context != NULL)
2724 break;
2725 }
Owen Taylor3473f882001-02-23 17:55:21 +00002726 }
2727 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002728
Owen Taylor3473f882001-02-23 17:55:21 +00002729 if (context == NULL) {
2730 return(NULL);
2731 }
2732
2733 /*
2734 * Allocate the Output buffer front-end.
2735 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002736 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002737 if (ret != NULL) {
2738 ret->context = context;
2739 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2740 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2741 }
2742 return(ret);
2743}
Daniel Veillard0335a842004-06-02 16:18:40 +00002744
2745/**
2746 * xmlOutputBufferCreateFilename:
2747 * @URI: a C string containing the URI or filename
2748 * @encoder: the encoding converter or NULL
2749 * @compression: the compression ration (0 none, 9 max).
2750 *
2751 * Create a buffered output for the progressive saving of a file
2752 * If filename is "-' then we use stdout as the output.
2753 * Automatic support for ZLIB/Compress compressed document is provided
2754 * by default if found at compile-time.
2755 * TODO: currently if compression is set, the library only support
2756 * writing to a local file.
2757 *
2758 * Returns the new output or NULL
2759 */
2760xmlOutputBufferPtr
2761xmlOutputBufferCreateFilename(const char *URI,
2762 xmlCharEncodingHandlerPtr encoder,
2763 int compression ATTRIBUTE_UNUSED) {
2764 if ((xmlOutputBufferCreateFilenameValue)) {
2765 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2766 }
2767 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2768}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002769#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002770
2771/**
2772 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002773 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002774 * @enc: the charset encoding if known
2775 *
2776 * Create a buffered parser input for the progressive parsing of a FILE *
2777 * buffered C I/O
2778 *
2779 * Returns the new parser input or NULL
2780 */
2781xmlParserInputBufferPtr
2782xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2783 xmlParserInputBufferPtr ret;
2784
2785 if (xmlInputCallbackInitialized == 0)
2786 xmlRegisterDefaultInputCallbacks();
2787
2788 if (file == NULL) return(NULL);
2789
2790 ret = xmlAllocParserInputBuffer(enc);
2791 if (ret != NULL) {
2792 ret->context = file;
2793 ret->readcallback = xmlFileRead;
2794 ret->closecallback = xmlFileFlush;
2795 }
2796
2797 return(ret);
2798}
2799
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002800#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002801/**
2802 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002803 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002804 * @encoder: the encoding converter or NULL
2805 *
2806 * Create a buffered output for the progressive saving to a FILE *
2807 * buffered C I/O
2808 *
2809 * Returns the new parser output or NULL
2810 */
2811xmlOutputBufferPtr
2812xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2813 xmlOutputBufferPtr ret;
2814
2815 if (xmlOutputCallbackInitialized == 0)
2816 xmlRegisterDefaultOutputCallbacks();
2817
2818 if (file == NULL) return(NULL);
2819
Daniel Veillardda3fee42008-09-01 13:08:57 +00002820 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002821 if (ret != NULL) {
2822 ret->context = file;
2823 ret->writecallback = xmlFileWrite;
2824 ret->closecallback = xmlFileFlush;
2825 }
2826
2827 return(ret);
2828}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002829
2830/**
2831 * xmlOutputBufferCreateBuffer:
2832 * @buffer: a xmlBufferPtr
2833 * @encoder: the encoding converter or NULL
2834 *
2835 * Create a buffered output for the progressive saving to a xmlBuffer
2836 *
2837 * Returns the new parser output or NULL
2838 */
2839xmlOutputBufferPtr
2840xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2841 xmlCharEncodingHandlerPtr encoder) {
2842 xmlOutputBufferPtr ret;
2843
2844 if (buffer == NULL) return(NULL);
2845
Nick Wellnhofer86615e42017-11-09 17:47:47 +01002846 ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer,
2847 encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002848
2849 return(ret);
2850}
2851
Daniel Veillarde258ade2012-08-06 11:16:30 +08002852/**
2853 * xmlOutputBufferGetContent:
2854 * @out: an xmlOutputBufferPtr
2855 *
2856 * Gives a pointer to the data currently held in the output buffer
2857 *
2858 * Returns a pointer to the data or NULL in case of error
2859 */
2860const xmlChar *
2861xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2862 if ((out == NULL) || (out->buffer == NULL))
2863 return(NULL);
2864
2865 return(xmlBufContent(out->buffer));
2866}
2867
2868/**
2869 * xmlOutputBufferGetSize:
2870 * @out: an xmlOutputBufferPtr
2871 *
2872 * Gives the length of the data currently held in the output buffer
2873 *
2874 * Returns 0 in case or error or no data is held, the size otherwise
2875 */
2876size_t
2877xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2878 if ((out == NULL) || (out->buffer == NULL))
2879 return(0);
2880
2881 return(xmlBufUse(out->buffer));
2882}
2883
2884
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002885#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002886
2887/**
2888 * xmlParserInputBufferCreateFd:
2889 * @fd: a file descriptor number
2890 * @enc: the charset encoding if known
2891 *
2892 * Create a buffered parser input for the progressive parsing for the input
2893 * from a file descriptor
2894 *
2895 * Returns the new parser input or NULL
2896 */
2897xmlParserInputBufferPtr
2898xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2899 xmlParserInputBufferPtr ret;
2900
2901 if (fd < 0) return(NULL);
2902
2903 ret = xmlAllocParserInputBuffer(enc);
2904 if (ret != NULL) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02002905 ret->context = (void *) (ptrdiff_t) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002906 ret->readcallback = xmlFdRead;
2907 ret->closecallback = xmlFdClose;
2908 }
2909
2910 return(ret);
2911}
2912
2913/**
2914 * xmlParserInputBufferCreateMem:
2915 * @mem: the memory input
2916 * @size: the length of the memory block
2917 * @enc: the charset encoding if known
2918 *
2919 * Create a buffered parser input for the progressive parsing for the input
2920 * from a memory area.
2921 *
2922 * Returns the new parser input or NULL
2923 */
2924xmlParserInputBufferPtr
2925xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2926 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002927 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002928
Nick Wellnhofer94f6ce82017-06-08 22:36:09 +02002929 if (size < 0) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002930 if (mem == NULL) return(NULL);
2931
2932 ret = xmlAllocParserInputBuffer(enc);
2933 if (ret != NULL) {
2934 ret->context = (void *) mem;
Vlad Tsyrklevich28f52fe2017-08-10 15:08:48 -07002935 ret->readcallback = xmlInputReadCallbackNop;
Owen Taylor3473f882001-02-23 17:55:21 +00002936 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002937 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00002938 if (errcode != 0) {
2939 xmlFree(ret);
2940 return(NULL);
2941 }
Owen Taylor3473f882001-02-23 17:55:21 +00002942 }
2943
2944 return(ret);
2945}
2946
2947/**
Daniel Veillard53350552003-09-18 13:35:51 +00002948 * xmlParserInputBufferCreateStatic:
2949 * @mem: the memory input
2950 * @size: the length of the memory block
2951 * @enc: the charset encoding if known
2952 *
2953 * Create a buffered parser input for the progressive parsing for the input
2954 * from an immutable memory area. This will not copy the memory area to
2955 * the buffer, but the memory is expected to be available until the end of
2956 * the parsing, this is useful for example when using mmap'ed file.
2957 *
2958 * Returns the new parser input or NULL
2959 */
2960xmlParserInputBufferPtr
2961xmlParserInputBufferCreateStatic(const char *mem, int size,
2962 xmlCharEncoding enc) {
2963 xmlParserInputBufferPtr ret;
2964
Nick Wellnhofer94f6ce82017-06-08 22:36:09 +02002965 if (size < 0) return(NULL);
Daniel Veillard53350552003-09-18 13:35:51 +00002966 if (mem == NULL) return(NULL);
2967
2968 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2969 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002970 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002971 return(NULL);
2972 }
2973 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002974 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002975 if (ret->buffer == NULL) {
2976 xmlFree(ret);
2977 return(NULL);
2978 }
2979 ret->encoder = xmlGetCharEncodingHandler(enc);
2980 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002981 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00002982 else
2983 ret->raw = NULL;
2984 ret->compressed = -1;
2985 ret->context = (void *) mem;
2986 ret->readcallback = NULL;
2987 ret->closecallback = NULL;
2988
2989 return(ret);
2990}
2991
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002992#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002993/**
Owen Taylor3473f882001-02-23 17:55:21 +00002994 * xmlOutputBufferCreateFd:
2995 * @fd: a file descriptor number
2996 * @encoder: the encoding converter or NULL
2997 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002998 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00002999 * to a file descriptor
3000 *
3001 * Returns the new parser output or NULL
3002 */
3003xmlOutputBufferPtr
3004xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3005 xmlOutputBufferPtr ret;
3006
3007 if (fd < 0) return(NULL);
3008
Daniel Veillardda3fee42008-09-01 13:08:57 +00003009 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003010 if (ret != NULL) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003011 ret->context = (void *) (ptrdiff_t) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003012 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003013 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003014 }
3015
3016 return(ret);
3017}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003018#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003019
3020/**
3021 * xmlParserInputBufferCreateIO:
3022 * @ioread: an I/O read function
3023 * @ioclose: an I/O close function
3024 * @ioctx: an I/O handler
3025 * @enc: the charset encoding if known
3026 *
3027 * Create a buffered parser input for the progressive parsing for the input
3028 * from an I/O handler
3029 *
3030 * Returns the new parser input or NULL
3031 */
3032xmlParserInputBufferPtr
3033xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3034 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3035 xmlParserInputBufferPtr ret;
3036
3037 if (ioread == NULL) return(NULL);
3038
3039 ret = xmlAllocParserInputBuffer(enc);
3040 if (ret != NULL) {
3041 ret->context = (void *) ioctx;
3042 ret->readcallback = ioread;
3043 ret->closecallback = ioclose;
3044 }
3045
3046 return(ret);
3047}
3048
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003049#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003050/**
3051 * xmlOutputBufferCreateIO:
3052 * @iowrite: an I/O write function
3053 * @ioclose: an I/O close function
3054 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003055 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003056 *
3057 * Create a buffered output for the progressive saving
3058 * to an I/O handler
3059 *
3060 * Returns the new parser output or NULL
3061 */
3062xmlOutputBufferPtr
3063xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3064 xmlOutputCloseCallback ioclose, void *ioctx,
3065 xmlCharEncodingHandlerPtr encoder) {
3066 xmlOutputBufferPtr ret;
3067
3068 if (iowrite == NULL) return(NULL);
3069
Daniel Veillardda3fee42008-09-01 13:08:57 +00003070 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003071 if (ret != NULL) {
3072 ret->context = (void *) ioctx;
3073 ret->writecallback = iowrite;
3074 ret->closecallback = ioclose;
3075 }
3076
3077 return(ret);
3078}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003079#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003080
3081/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003082 * xmlParserInputBufferCreateFilenameDefault:
3083 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3084 *
3085 * Registers a callback for URI input file handling
3086 *
3087 * Returns the old value of the registration function
3088 */
3089xmlParserInputBufferCreateFilenameFunc
3090xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3091{
3092 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3093 if (old == NULL) {
3094 old = __xmlParserInputBufferCreateFilename;
3095 }
3096
3097 xmlParserInputBufferCreateFilenameValue = func;
3098 return(old);
3099}
3100
3101/**
3102 * xmlOutputBufferCreateFilenameDefault:
3103 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3104 *
3105 * Registers a callback for URI output file handling
3106 *
3107 * Returns the old value of the registration function
3108 */
3109xmlOutputBufferCreateFilenameFunc
3110xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3111{
3112 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3113#ifdef LIBXML_OUTPUT_ENABLED
3114 if (old == NULL) {
3115 old = __xmlOutputBufferCreateFilename;
3116 }
3117#endif
3118 xmlOutputBufferCreateFilenameValue = func;
3119 return(old);
3120}
3121
3122/**
Owen Taylor3473f882001-02-23 17:55:21 +00003123 * xmlParserInputBufferPush:
3124 * @in: a buffered parser input
3125 * @len: the size in bytes of the array.
3126 * @buf: an char array
3127 *
3128 * Push the content of the arry in the input buffer
3129 * This routine handle the I18N transcoding to internal UTF-8
3130 * This is used when operating the parser in progressive (push) mode.
3131 *
3132 * Returns the number of chars read and stored in the buffer, or -1
3133 * in case of error.
3134 */
3135int
3136xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3137 int len, const char *buf) {
3138 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003139 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003140
3141 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003142 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003143 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003144 unsigned int use;
3145
Owen Taylor3473f882001-02-23 17:55:21 +00003146 /*
3147 * Store the data in the incoming raw buffer
3148 */
3149 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003150 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003151 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003152 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003153 if (ret != 0)
3154 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003155
3156 /*
3157 * convert as much as possible to the parser reading buffer.
3158 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003159 use = xmlBufUse(in->raw);
Joel Hockey6e6ae5d2018-01-02 21:47:35 -08003160 nbchars = xmlCharEncInput(in, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00003161 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003162 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003163 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003164 return(-1);
3165 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003166 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003167 } else {
3168 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003169 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003170 if (ret != 0)
3171 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003172 }
3173#ifdef DEBUG_INPUT
3174 xmlGenericError(xmlGenericErrorContext,
3175 "I/O: pushed %d chars, buffer %d/%d\n",
Roumen Petrov89b6f732012-08-04 05:09:56 +03003176 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003177#endif
3178 return(nbchars);
3179}
3180
3181/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003182 * endOfInput:
3183 *
3184 * When reading from an Input channel indicated end of file or error
3185 * don't reread from it again.
3186 */
3187static int
3188endOfInput (void * context ATTRIBUTE_UNUSED,
3189 char * buffer ATTRIBUTE_UNUSED,
3190 int len ATTRIBUTE_UNUSED) {
3191 return(0);
3192}
3193
3194/**
Owen Taylor3473f882001-02-23 17:55:21 +00003195 * xmlParserInputBufferGrow:
3196 * @in: a buffered parser input
3197 * @len: indicative value of the amount of chars to read
3198 *
3199 * Grow up the content of the input buffer, the old data are preserved
3200 * This routine handle the I18N transcoding to internal UTF-8
3201 * This routine is used when operating the parser in normal (pull) mode
3202 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003203 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003204 * onto in->buffer or in->raw
3205 *
3206 * Returns the number of chars read and stored in the buffer, or -1
3207 * in case of error.
3208 */
3209int
3210xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3211 char *buffer = NULL;
3212 int res = 0;
3213 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003214
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003215 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003216 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003217 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003218
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003219 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003220 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003221 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003222 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003223 }
Owen Taylor3473f882001-02-23 17:55:21 +00003224
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003225 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3226 xmlIOErrMemory("growing input buffer");
3227 in->error = XML_ERR_NO_MEMORY;
3228 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003229 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003230 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003231
3232 /*
3233 * Call the read method for this I/O type.
3234 */
3235 if (in->readcallback != NULL) {
3236 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003237 if (res <= 0)
3238 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003239 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003240 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003241 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003242 return(-1);
3243 }
3244 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003245 return(-1);
3246 }
Daniel Veillard63588f42013-05-10 14:01:46 +08003247
3248 /*
3249 * try to establish compressed status of input if not done already
3250 */
3251 if (in->compressed == -1) {
Daniel Veillard18b89882015-11-03 15:46:29 +08003252#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08003253 if (in->readcallback == xmlXzfileRead)
3254 in->compressed = __libxml2_xzcompressed(in->context);
3255#endif
3256 }
3257
Owen Taylor3473f882001-02-23 17:55:21 +00003258 len = res;
3259 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003260 unsigned int use;
3261
Owen Taylor3473f882001-02-23 17:55:21 +00003262 /*
3263 * Store the data in the incoming raw buffer
3264 */
3265 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003266 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003267 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003268 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003269 if (res != 0)
3270 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003271
3272 /*
3273 * convert as much as possible to the parser reading buffer.
3274 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003275 use = xmlBufUse(in->raw);
Joel Hockey6e6ae5d2018-01-02 21:47:35 -08003276 nbchars = xmlCharEncInput(in, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00003277 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003278 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003279 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003280 return(-1);
3281 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003282 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003283 } else {
3284 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003285 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003286 }
3287#ifdef DEBUG_INPUT
3288 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003289 "I/O: read %d chars, buffer %d\n",
3290 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003291#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003292 return(nbchars);
3293}
3294
3295/**
3296 * xmlParserInputBufferRead:
3297 * @in: a buffered parser input
3298 * @len: indicative value of the amount of chars to read
3299 *
3300 * Refresh the content of the input buffer, the old data are considered
3301 * consumed
3302 * This routine handle the I18N transcoding to internal UTF-8
3303 *
3304 * Returns the number of chars read and stored in the buffer, or -1
3305 * in case of error.
3306 */
3307int
3308xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003309 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003310 if (in->readcallback != NULL)
3311 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003312 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003313 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003314 else
3315 return(-1);
3316}
3317
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003318#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003319/**
3320 * xmlOutputBufferWrite:
3321 * @out: a buffered parser output
3322 * @len: the size in bytes of the array.
3323 * @buf: an char array
3324 *
3325 * Write the content of the array in the output I/O buffer
3326 * This routine handle the I18N transcoding from internal UTF-8
3327 * The buffer is lossless, i.e. will store in case of partial
3328 * or delayed writes.
3329 *
3330 * Returns the number of chars immediately written, or -1
3331 * in case of error.
3332 */
3333int
3334xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3335 int nbchars = 0; /* number of chars to output to I/O */
3336 int ret; /* return from function call */
3337 int written = 0; /* number of char written to I/O so far */
3338 int chunk; /* number of byte curreent processed from buf */
3339
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003340 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003341 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003342 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003343
3344 do {
3345 chunk = len;
3346 if (chunk > 4 * MINLEN)
3347 chunk = 4 * MINLEN;
3348
3349 /*
3350 * first handle encoding stuff.
3351 */
3352 if (out->encoder != NULL) {
3353 /*
3354 * Store the data in the incoming raw buffer
3355 */
3356 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003357 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003358 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003359 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003360 if (ret != 0)
3361 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003362
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003363 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003364 goto done;
3365
3366 /*
3367 * convert as much as possible to the parser reading buffer.
3368 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003369 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003370 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003371 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003372 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003373 return(-1);
3374 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003375 nbchars = xmlBufUse(out->conv);
Owen Taylor3473f882001-02-23 17:55:21 +00003376 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003377 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003378 if (ret != 0)
3379 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003380 nbchars = xmlBufUse(out->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003381 }
3382 buf += chunk;
3383 len -= chunk;
3384
3385 if ((nbchars < MINLEN) && (len <= 0))
3386 goto done;
3387
3388 if (out->writecallback) {
3389 /*
3390 * second write the stuff to the I/O channel
3391 */
3392 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003393 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003394 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003395 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003396 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003397 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003398 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003399 (const char *)xmlBufContent(out->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003400 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003401 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003402 }
3403 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003404 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003405 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003406 return(ret);
3407 }
3408 out->written += ret;
3409 }
3410 written += nbchars;
3411 } while (len > 0);
3412
3413done:
3414#ifdef DEBUG_INPUT
3415 xmlGenericError(xmlGenericErrorContext,
3416 "I/O: wrote %d chars\n", written);
3417#endif
3418 return(written);
3419}
3420
3421/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003422 * xmlEscapeContent:
3423 * @out: a pointer to an array of bytes to store the result
3424 * @outlen: the length of @out
3425 * @in: a pointer to an array of unescaped UTF-8 bytes
3426 * @inlen: the length of @in
3427 *
3428 * Take a block of UTF-8 chars in and escape them.
3429 * Returns 0 if success, or -1 otherwise
3430 * The value of @inlen after return is the number of octets consumed
3431 * if the return value is positive, else unpredictable.
3432 * The value of @outlen after return is the number of octets consumed.
3433 */
3434static int
3435xmlEscapeContent(unsigned char* out, int *outlen,
3436 const xmlChar* in, int *inlen) {
3437 unsigned char* outstart = out;
3438 const unsigned char* base = in;
3439 unsigned char* outend = out + *outlen;
3440 const unsigned char* inend;
3441
3442 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003443
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003444 while ((in < inend) && (out < outend)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003445 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003446 if (outend - out < 4) break;
3447 *out++ = '&';
3448 *out++ = 'l';
3449 *out++ = 't';
3450 *out++ = ';';
3451 } else if (*in == '>') {
3452 if (outend - out < 4) break;
3453 *out++ = '&';
3454 *out++ = 'g';
3455 *out++ = 't';
3456 *out++ = ';';
3457 } else if (*in == '&') {
3458 if (outend - out < 5) break;
3459 *out++ = '&';
3460 *out++ = 'a';
3461 *out++ = 'm';
3462 *out++ = 'p';
3463 *out++ = ';';
3464 } else if (*in == '\r') {
3465 if (outend - out < 5) break;
3466 *out++ = '&';
3467 *out++ = '#';
3468 *out++ = '1';
3469 *out++ = '3';
3470 *out++ = ';';
3471 } else {
3472 *out++ = (unsigned char) *in;
3473 }
3474 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003475 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003476 *outlen = out - outstart;
3477 *inlen = in - base;
3478 return(0);
3479}
3480
3481/**
3482 * xmlOutputBufferWriteEscape:
3483 * @out: a buffered parser output
3484 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003485 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003486 *
3487 * Write the content of the string in the output I/O buffer
3488 * This routine escapes the caracters and then handle the I18N
3489 * transcoding from internal UTF-8
3490 * The buffer is lossless, i.e. will store in case of partial
3491 * or delayed writes.
3492 *
3493 * Returns the number of chars immediately written, or -1
3494 * in case of error.
3495 */
3496int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003497xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3498 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003499 int nbchars = 0; /* number of chars to output to I/O */
3500 int ret; /* return from function call */
3501 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003502 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003503 int chunk; /* number of byte currently processed from str */
3504 int len; /* number of bytes in str */
3505 int cons; /* byte from str consumed */
3506
Daniel Veillardce244ad2004-11-05 10:03:46 +00003507 if ((out == NULL) || (out->error) || (str == NULL) ||
3508 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003509 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3510 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003511 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003512 if (len < 0) return(0);
3513 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003514 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003515
3516 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003517 oldwritten = written;
3518
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003519 /*
3520 * how many bytes to consume and how many bytes to store.
3521 */
3522 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003523 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003524
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003525 /*
3526 * make sure we have enough room to save first, if this is
3527 * not the case force a flush, but make sure we stay in the loop
3528 */
3529 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003530 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003531 return(-1);
3532 oldwritten = -1;
3533 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003534 }
3535
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003536 /*
3537 * first handle encoding stuff.
3538 */
3539 if (out->encoder != NULL) {
3540 /*
3541 * Store the data in the incoming raw buffer
3542 */
3543 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003544 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003545 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003546 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003547 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003548 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003549 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003550 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003551
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003552 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003553 goto done;
3554
3555 /*
3556 * convert as much as possible to the output buffer.
3557 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003558 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003559 if ((ret < 0) && (ret != -3)) {
3560 xmlIOErr(XML_IO_ENCODER, NULL);
3561 out->error = XML_IO_ENCODER;
3562 return(-1);
3563 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003564 nbchars = xmlBufUse(out->conv);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003565 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003566 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003567 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003568 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003569 xmlBufAddLen(out->buffer, chunk);
3570 nbchars = xmlBufUse(out->buffer);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003571 }
3572 str += cons;
3573 len -= cons;
3574
3575 if ((nbchars < MINLEN) && (len <= 0))
3576 goto done;
3577
3578 if (out->writecallback) {
3579 /*
3580 * second write the stuff to the I/O channel
3581 */
3582 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003583 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003584 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003585 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003586 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003587 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003588 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003589 (const char *)xmlBufContent(out->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003590 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003591 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003592 }
3593 if (ret < 0) {
3594 xmlIOErr(XML_IO_WRITE, NULL);
3595 out->error = XML_IO_WRITE;
3596 return(ret);
3597 }
3598 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003599 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3600 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003601 }
3602 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003603 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003604
3605done:
3606#ifdef DEBUG_INPUT
3607 xmlGenericError(xmlGenericErrorContext,
3608 "I/O: wrote %d chars\n", written);
3609#endif
3610 return(written);
3611}
3612
3613/**
Owen Taylor3473f882001-02-23 17:55:21 +00003614 * xmlOutputBufferWriteString:
3615 * @out: a buffered parser output
3616 * @str: a zero terminated C string
3617 *
3618 * Write the content of the string in the output I/O buffer
3619 * This routine handle the I18N transcoding from internal UTF-8
3620 * The buffer is lossless, i.e. will store in case of partial
3621 * or delayed writes.
3622 *
3623 * Returns the number of chars immediately written, or -1
3624 * in case of error.
3625 */
3626int
3627xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3628 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003629
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003630 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003631 if (str == NULL)
3632 return(-1);
3633 len = strlen(str);
3634
3635 if (len > 0)
3636 return(xmlOutputBufferWrite(out, len, str));
3637 return(len);
3638}
3639
3640/**
3641 * xmlOutputBufferFlush:
3642 * @out: a buffered output
3643 *
3644 * flushes the output I/O channel
3645 *
3646 * Returns the number of byte written or -1 in case of error.
3647 */
3648int
3649xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3650 int nbchars = 0, ret = 0;
3651
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003652 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003653 /*
3654 * first handle encoding stuff.
3655 */
3656 if ((out->conv != NULL) && (out->encoder != NULL)) {
3657 /*
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003658 * convert as much as possible to the parser output buffer.
Owen Taylor3473f882001-02-23 17:55:21 +00003659 */
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003660 do {
3661 nbchars = xmlCharEncOutput(out, 0);
3662 if (nbchars < 0) {
3663 xmlIOErr(XML_IO_ENCODER, NULL);
3664 out->error = XML_IO_ENCODER;
3665 return(-1);
3666 }
3667 } while (nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003668 }
3669
3670 /*
3671 * second flush the stuff to the I/O channel
3672 */
3673 if ((out->conv != NULL) && (out->encoder != NULL) &&
3674 (out->writecallback != NULL)) {
3675 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003676 (const char *)xmlBufContent(out->conv),
3677 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003678 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003679 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003680 } else if (out->writecallback != NULL) {
3681 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003682 (const char *)xmlBufContent(out->buffer),
3683 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003684 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003685 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003686 }
3687 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003688 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003689 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003690 return(ret);
3691 }
3692 out->written += ret;
3693
3694#ifdef DEBUG_INPUT
3695 xmlGenericError(xmlGenericErrorContext,
3696 "I/O: flushed %d chars\n", ret);
3697#endif
3698 return(ret);
3699}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003700#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003701
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003702/**
Owen Taylor3473f882001-02-23 17:55:21 +00003703 * xmlParserGetDirectory:
3704 * @filename: the path to a file
3705 *
3706 * lookup the directory for that file
3707 *
3708 * Returns a new allocated string containing the directory, or NULL.
3709 */
3710char *
3711xmlParserGetDirectory(const char *filename) {
3712 char *ret = NULL;
3713 char dir[1024];
3714 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003715
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003716#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3717 return NULL;
3718#endif
3719
Owen Taylor3473f882001-02-23 17:55:21 +00003720 if (xmlInputCallbackInitialized == 0)
3721 xmlRegisterDefaultInputCallbacks();
3722
3723 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003724
Nick Wellnhofere3890542017-10-09 00:20:01 +02003725#if defined(_WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003726# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3727#else
3728# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003729#endif
3730
3731 strncpy(dir, filename, 1023);
3732 dir[1023] = 0;
3733 cur = &dir[strlen(dir)];
3734 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003735 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003736 cur --;
3737 }
Rob Richardsf779da32007-08-14 09:41:21 +00003738 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003739 if (cur == dir) dir[1] = 0;
3740 else *cur = 0;
3741 ret = xmlMemStrdup(dir);
3742 } else {
3743 if (getcwd(dir, 1024) != NULL) {
3744 dir[1023] = 0;
3745 ret = xmlMemStrdup(dir);
3746 }
3747 }
3748 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003749#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003750}
3751
3752/****************************************************************
3753 * *
3754 * External entities loading *
3755 * *
3756 ****************************************************************/
3757
Daniel Veillarda840b692003-10-19 13:35:37 +00003758/**
3759 * xmlCheckHTTPInput:
3760 * @ctxt: an XML parser context
3761 * @ret: an XML parser input
3762 *
3763 * Check an input in case it was created from an HTTP stream, in that
3764 * case it will handle encoding and update of the base URL in case of
3765 * redirection. It also checks for HTTP errors in which case the input
3766 * is cleanly freed up and an appropriate error is raised in context
3767 *
3768 * Returns the input or NULL in case of HTTP error.
3769 */
3770xmlParserInputPtr
3771xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3772#ifdef LIBXML_HTTP_ENABLED
3773 if ((ret != NULL) && (ret->buf != NULL) &&
3774 (ret->buf->readcallback == xmlIOHTTPRead) &&
3775 (ret->buf->context != NULL)) {
3776 const char *encoding;
3777 const char *redir;
3778 const char *mime;
3779 int code;
3780
3781 code = xmlNanoHTTPReturnCode(ret->buf->context);
3782 if (code >= 400) {
3783 /* fatal error */
3784 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003785 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003786 (const char *) ret->filename);
3787 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003788 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003789 xmlFreeInputStream(ret);
3790 ret = NULL;
3791 } else {
3792
3793 mime = xmlNanoHTTPMimeType(ret->buf->context);
3794 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3795 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3796 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3797 if (encoding != NULL) {
3798 xmlCharEncodingHandlerPtr handler;
3799
3800 handler = xmlFindCharEncodingHandler(encoding);
3801 if (handler != NULL) {
3802 xmlSwitchInputEncoding(ctxt, ret, handler);
3803 } else {
3804 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3805 "Unknown encoding %s",
3806 BAD_CAST encoding, NULL);
3807 }
3808 if (ret->encoding == NULL)
3809 ret->encoding = xmlStrdup(BAD_CAST encoding);
3810 }
3811#if 0
3812 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3813#endif
3814 }
3815 redir = xmlNanoHTTPRedir(ret->buf->context);
3816 if (redir != NULL) {
3817 if (ret->filename != NULL)
3818 xmlFree((xmlChar *) ret->filename);
3819 if (ret->directory != NULL) {
3820 xmlFree((xmlChar *) ret->directory);
3821 ret->directory = NULL;
3822 }
3823 ret->filename =
3824 (char *) xmlStrdup((const xmlChar *) redir);
3825 }
3826 }
3827 }
3828#endif
3829 return(ret);
3830}
3831
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003832static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003833 const char *path;
3834
3835 if (URL == NULL)
3836 return(0);
3837
Daniel Veillardf4862f02002-09-10 11:13:43 +00003838 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003839#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003840 path = &URL[17];
3841#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003842 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003843#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003844 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003845#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003846 path = &URL[8];
3847#else
3848 path = &URL[7];
3849#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003850 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003851 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003852
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003853 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003854}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003855
Daniel Veillardad4e2962006-09-21 08:36:38 +00003856#ifdef LIBXML_CATALOG_ENABLED
3857
3858/**
3859 * xmlResolveResourceFromCatalog:
3860 * @URL: the URL for the entity to load
3861 * @ID: the System ID for the entity to load
3862 * @ctxt: the context in which the entity is called or NULL
3863 *
3864 * Resolves the URL and ID against the appropriate catalog.
3865 * This function is used by xmlDefaultExternalEntityLoader and
3866 * xmlNoNetExternalEntityLoader.
3867 *
3868 * Returns a new allocated URL, or NULL.
3869 */
William M. Brack38d452a2007-05-22 16:00:06 +00003870static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003871xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3872 xmlParserCtxtPtr ctxt) {
3873 xmlChar *resource = NULL;
3874 xmlCatalogAllow pref;
3875
3876 /*
3877 * If the resource doesn't exists as a file,
3878 * try to load it from the resource pointed in the catalogs
3879 */
3880 pref = xmlCatalogGetDefaults();
3881
3882 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3883 /*
3884 * Do a local lookup
3885 */
3886 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3887 ((pref == XML_CATA_ALLOW_ALL) ||
3888 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3889 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3890 (const xmlChar *)ID,
3891 (const xmlChar *)URL);
3892 }
3893 /*
3894 * Try a global lookup
3895 */
3896 if ((resource == NULL) &&
3897 ((pref == XML_CATA_ALLOW_ALL) ||
3898 (pref == XML_CATA_ALLOW_GLOBAL))) {
3899 resource = xmlCatalogResolve((const xmlChar *)ID,
3900 (const xmlChar *)URL);
3901 }
3902 if ((resource == NULL) && (URL != NULL))
3903 resource = xmlStrdup((const xmlChar *) URL);
3904
3905 /*
3906 * TODO: do an URI lookup on the reference
3907 */
3908 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3909 xmlChar *tmp = NULL;
3910
3911 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3912 ((pref == XML_CATA_ALLOW_ALL) ||
3913 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3914 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3915 }
3916 if ((tmp == NULL) &&
3917 ((pref == XML_CATA_ALLOW_ALL) ||
3918 (pref == XML_CATA_ALLOW_GLOBAL))) {
3919 tmp = xmlCatalogResolveURI(resource);
3920 }
3921
3922 if (tmp != NULL) {
3923 xmlFree(resource);
3924 resource = tmp;
3925 }
3926 }
3927 }
3928
3929 return resource;
3930}
3931
3932#endif
3933
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003934/**
Owen Taylor3473f882001-02-23 17:55:21 +00003935 * xmlDefaultExternalEntityLoader:
3936 * @URL: the URL for the entity to load
3937 * @ID: the System ID for the entity to load
3938 * @ctxt: the context in which the entity is called or NULL
3939 *
3940 * By default we don't load external entitites, yet.
3941 *
3942 * Returns a new allocated xmlParserInputPtr, or NULL.
3943 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003944static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003945xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003946 xmlParserCtxtPtr ctxt)
3947{
Owen Taylor3473f882001-02-23 17:55:21 +00003948 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003949 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003950
Owen Taylor3473f882001-02-23 17:55:21 +00003951#ifdef DEBUG_EXTERNAL_ENTITIES
3952 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003953 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003954#endif
Nick Wellnhofer030b1f72017-06-06 15:53:42 +02003955 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
Daniel Veillard61b93382003-11-03 14:28:31 +00003956 int options = ctxt->options;
3957
Nick Wellnhofer030b1f72017-06-06 15:53:42 +02003958 ctxt->options -= XML_PARSE_NONET;
3959 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3960 ctxt->options = options;
3961 return(ret);
Daniel Veillard61b93382003-11-03 14:28:31 +00003962 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003963#ifdef LIBXML_CATALOG_ENABLED
3964 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003965#endif
3966
3967 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003968 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003969
3970 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003971 if (ID == NULL)
3972 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003973 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003974 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003975 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003976 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003977 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003978 xmlFree(resource);
3979 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003980}
3981
3982static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3983 xmlDefaultExternalEntityLoader;
3984
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003985/**
Owen Taylor3473f882001-02-23 17:55:21 +00003986 * xmlSetExternalEntityLoader:
3987 * @f: the new entity resolver function
3988 *
3989 * Changes the defaultexternal entity resolver function for the application
3990 */
3991void
3992xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3993 xmlCurrentExternalEntityLoader = f;
3994}
3995
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003996/**
Owen Taylor3473f882001-02-23 17:55:21 +00003997 * xmlGetExternalEntityLoader:
3998 *
3999 * Get the default external entity resolver function for the application
4000 *
4001 * Returns the xmlExternalEntityLoader function pointer
4002 */
4003xmlExternalEntityLoader
4004xmlGetExternalEntityLoader(void) {
4005 return(xmlCurrentExternalEntityLoader);
4006}
4007
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004008/**
Owen Taylor3473f882001-02-23 17:55:21 +00004009 * xmlLoadExternalEntity:
4010 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004011 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004012 * @ctxt: the context in which the entity is called or NULL
4013 *
4014 * Load an external entity, note that the use of this function for
4015 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004016 *
4017 * Returns the xmlParserInputPtr or NULL
4018 */
4019xmlParserInputPtr
4020xmlLoadExternalEntity(const char *URL, const char *ID,
4021 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004022 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004023 char *canonicFilename;
4024 xmlParserInputPtr ret;
4025
4026 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4027 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004028 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004029 return(NULL);
4030 }
4031
4032 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4033 xmlFree(canonicFilename);
4034 return(ret);
4035 }
Owen Taylor3473f882001-02-23 17:55:21 +00004036 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4037}
4038
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004039/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004040 * *
4041 * Disabling Network access *
4042 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004043 ************************************************************************/
4044
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004045/**
4046 * xmlNoNetExternalEntityLoader:
4047 * @URL: the URL for the entity to load
4048 * @ID: the System ID for the entity to load
4049 * @ctxt: the context in which the entity is called or NULL
4050 *
4051 * A specific entity loader disabling network accesses, though still
4052 * allowing local catalog accesses for resolution.
4053 *
4054 * Returns a new allocated xmlParserInputPtr, or NULL.
4055 */
4056xmlParserInputPtr
4057xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4058 xmlParserCtxtPtr ctxt) {
4059 xmlParserInputPtr input = NULL;
4060 xmlChar *resource = NULL;
4061
4062#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004063 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004064#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004065
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004066 if (resource == NULL)
4067 resource = (xmlChar *) URL;
4068
4069 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004070 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4071 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004072 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004073 if (resource != (xmlChar *) URL)
4074 xmlFree(resource);
4075 return(NULL);
4076 }
4077 }
4078 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4079 if (resource != (xmlChar *) URL)
4080 xmlFree(resource);
4081 return(input);
4082}
4083
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004084#define bottom_xmlIO
4085#include "elfgcchack.h"