blob: c510a7e9d40f167cd8c3e4861fc9715eced861a0 [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 */
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700188 "address in use", /* EADDRINUSE */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000189 "already in use", /* EALREADY */
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700190 "unknown address family", /* 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:
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700227 * @extra: extra information
Daniel Veillard05d987b2003-10-08 11:54:57 +0000228 *
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 * @
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700241 * @extra: extra information
Daniel Veillard05d987b2003-10-08 11:54:57 +0000242 *
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
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700419 * @extra: extra information
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000420 *
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
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700432 * @extra: extra information
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000433 *
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}
Haibo Huangcfd91dc2020-07-30 23:01:33 -0700563
564/**
565 * xmlPopOutputCallbacks:
566 *
567 * Remove the top output callbacks from the output stack. This includes the
568 * compiled-in I/O.
569 *
570 * Returns the number of output callback registered or -1 in case of error.
571 */
572int
573xmlPopOutputCallbacks(void)
574{
575 if (!xmlOutputCallbackInitialized)
576 return(-1);
577
578 if (xmlOutputCallbackNr <= 0)
579 return(-1);
580
581 xmlOutputCallbackNr--;
582 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = NULL;
583 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = NULL;
584 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = NULL;
585 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = NULL;
586
587 return(xmlOutputCallbackNr);
588}
589
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000590#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000591
Owen Taylor3473f882001-02-23 17:55:21 +0000592/************************************************************************
593 * *
594 * Standard I/O for file accesses *
595 * *
596 ************************************************************************/
597
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000598#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
599
600/**
601 * xmlWrapOpenUtf8:
602 * @path: the path in utf-8 encoding
603 * @mode: type of access (0 - read, 1 - write)
604 *
605 * function opens the file specified by @path
606 *
607 */
608static FILE*
609xmlWrapOpenUtf8(const char *path,int mode)
610{
611 FILE *fd = NULL;
612 wchar_t *wPath;
613
614 wPath = __xmlIOWin32UTF8ToWChar(path);
615 if(wPath)
616 {
617 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
618 xmlFree(wPath);
619 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000620 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000621 if(fd == NULL)
622 fd = fopen(path, mode ? "wb" : "rb");
623
624 return fd;
625}
626
Nick Wellnhofercb5541c2017-11-13 17:08:38 +0100627#ifdef LIBXML_ZLIB_ENABLED
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200628static gzFile
629xmlWrapGzOpenUtf8(const char *path, const char *mode)
630{
631 gzFile fd;
632 wchar_t *wPath;
633
634 fd = gzopen (path, mode);
635 if (fd)
636 return fd;
637
638 wPath = __xmlIOWin32UTF8ToWChar(path);
639 if(wPath)
640 {
641 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
642#ifdef _O_BINARY
643 m |= (strstr(mode, "b") ? _O_BINARY : 0);
644#endif
645 d = _wopen(wPath, m);
646 if (d >= 0)
647 fd = gzdopen(d, mode);
648 xmlFree(wPath);
649 }
650
651 return fd;
652}
Rob Richards6c61e022009-08-12 11:41:27 -0400653#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200654
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000655/**
656 * xmlWrapStatUtf8:
657 * @path: the path in utf-8 encoding
658 * @info: structure that stores results
659 *
660 * function obtains information about the file or directory
661 *
662 */
663static int
Nick Wellnhofer56723972017-10-09 15:35:32 +0200664xmlWrapStatUtf8(const char *path, struct _stat *info) {
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000665 int retval = -1;
666 wchar_t *wPath;
667
668 wPath = __xmlIOWin32UTF8ToWChar(path);
Nick Wellnhofer56723972017-10-09 15:35:32 +0200669 if (wPath) {
670 retval = _wstat(wPath, info);
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000671 xmlFree(wPath);
672 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000673 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000674 if(retval < 0)
Nick Wellnhofer56723972017-10-09 15:35:32 +0200675 retval = _stat(path, info);
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000676 return retval;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000677}
678
679#endif
680
Owen Taylor3473f882001-02-23 17:55:21 +0000681/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000682 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000683 * @path: the path to check
684 *
685 * function checks to see if @path is a valid source
686 * (file, socket...) for XML.
687 *
688 * if stat is not available on the target machine,
689 * returns 1. if stat fails, returns 0 (if calling
690 * stat on the filename fails, it can't be right).
691 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000692 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000693 */
694
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000695int
Owen Taylor3473f882001-02-23 17:55:21 +0000696xmlCheckFilename (const char *path)
697{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000698#ifdef HAVE_STAT
Nick Wellnhofer56723972017-10-09 15:35:32 +0200699#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
700 struct _stat stat_buffer;
701#else
Michael Stahl55b899a2012-09-07 12:14:00 +0800702 struct stat stat_buffer;
Daniel Veillard0b309952006-05-02 20:34:38 +0000703#endif
Nick Wellnhofer56723972017-10-09 15:35:32 +0200704#endif
Michael Stahl55b899a2012-09-07 12:14:00 +0800705 if (path == NULL)
706 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000707
Owen Taylor3473f882001-02-23 17:55:21 +0000708#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000709#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Michael Stahl55b899a2012-09-07 12:14:00 +0800710 /*
711 * On Windows stat and wstat do not work with long pathname,
712 * which start with '\\?\'
713 */
714 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
715 (path[3] == '\\') )
716 return 1;
717
Nick Wellnhofer56723972017-10-09 15:35:32 +0200718 if (xmlWrapStatUtf8(path, &stat_buffer) == -1)
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000719 return 0;
720#else
Owen Taylor3473f882001-02-23 17:55:21 +0000721 if (stat(path, &stat_buffer) == -1)
722 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000723#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000724#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000725 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000726 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000727#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000728#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000729 return 1;
730}
731
Daniel Veillard7a72f4a2014-10-13 16:23:24 +0800732/**
Vlad Tsyrklevich28f52fe2017-08-10 15:08:48 -0700733 * xmlInputReadCallbackNop:
Daniel Veillard7a72f4a2014-10-13 16:23:24 +0800734 *
Vlad Tsyrklevich28f52fe2017-08-10 15:08:48 -0700735 * No Operation xmlInputReadCallback function, does nothing.
Daniel Veillard7a72f4a2014-10-13 16:23:24 +0800736 *
737 * Returns zero
738 */
Daniel Veillard153cf152012-10-26 13:50:47 +0800739int
Vlad Tsyrklevich28f52fe2017-08-10 15:08:48 -0700740xmlInputReadCallbackNop(void *context ATTRIBUTE_UNUSED,
741 char *buffer ATTRIBUTE_UNUSED,
742 int len ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000743 return(0);
744}
745
746/**
Owen Taylor3473f882001-02-23 17:55:21 +0000747 * xmlFdRead:
748 * @context: the I/O context
749 * @buffer: where to drop data
750 * @len: number of bytes to read
751 *
752 * Read @len bytes to @buffer from the I/O channel.
753 *
754 * Returns the number of bytes written
755 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000756static int
Owen Taylor3473f882001-02-23 17:55:21 +0000757xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000758 int ret;
759
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200760 ret = read((int) (ptrdiff_t) context, &buffer[0], len);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000761 if (ret < 0) xmlIOErr(0, "read()");
762 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000763}
764
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000765#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000766/**
767 * xmlFdWrite:
768 * @context: the I/O context
769 * @buffer: where to get data
770 * @len: number of bytes to write
771 *
772 * Write @len bytes from @buffer to the I/O channel.
773 *
774 * Returns the number of bytes written
775 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000776static int
Owen Taylor3473f882001-02-23 17:55:21 +0000777xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000778 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000779
Daniel Veillard9b693b42005-10-28 14:54:17 +0000780 if (len > 0) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200781 ret = write((int) (ptrdiff_t) context, &buffer[0], len);
Daniel Veillard9b693b42005-10-28 14:54:17 +0000782 if (ret < 0) xmlIOErr(0, "write()");
783 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000784 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000785}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000786#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000787
788/**
789 * xmlFdClose:
790 * @context: the I/O context
791 *
792 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000793 *
794 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000795 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000796static int
Owen Taylor3473f882001-02-23 17:55:21 +0000797xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000798 int ret;
Nick Wellnhoferd422b952017-10-09 13:37:42 +0200799 ret = close((int) (ptrdiff_t) context);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000800 if (ret < 0) xmlIOErr(0, "close()");
801 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000802}
803
804/**
805 * xmlFileMatch:
806 * @filename: the URI for matching
807 *
808 * input from FILE *
809 *
810 * Returns 1 if matches, 0 otherwise
811 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000812int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000813xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000814 return(1);
815}
816
817/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000818 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000819 * @filename: the URI for matching
820 *
821 * input from FILE *, supports compressed input
822 * if @filename is " " then the standard input is used
823 *
824 * Returns an I/O context or NULL in case of error
825 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000826static void *
827xmlFileOpen_real (const char *filename) {
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800828 const char *path = filename;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000829 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000830
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000831 if (filename == NULL)
832 return(NULL);
833
Owen Taylor3473f882001-02-23 17:55:21 +0000834 if (!strcmp(filename, "-")) {
835 fd = stdin;
836 return((void *) fd);
837 }
838
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000839 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000840#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000841 path = &filename[17];
842#else
Owen Taylor3473f882001-02-23 17:55:21 +0000843 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000844#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000845 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000846#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000847 path = &filename[8];
848#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000849 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000850#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000851 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
852 /* lots of generators seems to lazy to read RFC 1738 */
853#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
854 path = &filename[6];
855#else
856 path = &filename[5];
857#endif
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800858 }
Owen Taylor3473f882001-02-23 17:55:21 +0000859
Stéphane Michaut454e3972017-08-28 14:30:43 +0200860 /* Do not check DDNAME on zOS ! */
861#if !defined(__MVS__)
Owen Taylor3473f882001-02-23 17:55:21 +0000862 if (!xmlCheckFilename(path))
863 return(NULL);
Stéphane Michaut454e3972017-08-28 14:30:43 +0200864#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000865
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000866#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Nick Wellnhofer56723972017-10-09 15:35:32 +0200867 fd = xmlWrapOpenUtf8(path, 0);
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000868#else
869 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000870#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000871 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000872 return((void *) fd);
873}
874
875/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000876 * xmlFileOpen:
877 * @filename: the URI for matching
878 *
879 * Wrapper around xmlFileOpen_real that try it with an unescaped
880 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000881 *
882 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000883 */
884void *
885xmlFileOpen (const char *filename) {
886 char *unescaped;
887 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000888
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000889 retval = xmlFileOpen_real(filename);
890 if (retval == NULL) {
891 unescaped = xmlURIUnescapeString(filename, 0, NULL);
892 if (unescaped != NULL) {
893 retval = xmlFileOpen_real(unescaped);
894 xmlFree(unescaped);
895 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000896 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000897
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000898 return retval;
899}
900
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000901#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000902/**
Owen Taylor3473f882001-02-23 17:55:21 +0000903 * xmlFileOpenW:
904 * @filename: the URI for matching
905 *
906 * output to from FILE *,
907 * if @filename is "-" then the standard output is used
908 *
909 * Returns an I/O context or NULL in case of error
910 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000911static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000912xmlFileOpenW (const char *filename) {
913 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000914 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000915
916 if (!strcmp(filename, "-")) {
917 fd = stdout;
918 return((void *) fd);
919 }
920
Daniel Veillardf4862f02002-09-10 11:13:43 +0000921 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000922#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000923 path = &filename[17];
924#else
Owen Taylor3473f882001-02-23 17:55:21 +0000925 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000926#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000927 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000928#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000929 path = &filename[8];
930#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000931 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000932#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200933 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000934 path = filename;
935
936 if (path == NULL)
937 return(NULL);
938
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000939#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Nick Wellnhofer56723972017-10-09 15:35:32 +0200940 fd = xmlWrapOpenUtf8(path, 1);
Stéphane Michaut454e3972017-08-28 14:30:43 +0200941#elif(__MVS__)
942 fd = fopen(path, "w");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000943#else
Stéphane Michaut454e3972017-08-28 14:30:43 +0200944 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000945#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000946
Stéphane Michaut454e3972017-08-28 14:30:43 +0200947 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000948 return((void *) fd);
949}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000950#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000951
952/**
953 * xmlFileRead:
954 * @context: the I/O context
955 * @buffer: where to drop data
956 * @len: number of bytes to write
957 *
958 * Read @len bytes to @buffer from the I/O channel.
959 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000960 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000961 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000962int
Owen Taylor3473f882001-02-23 17:55:21 +0000963xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000964 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200965 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +0000966 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000967 ret = fread(&buffer[0], 1, len, (FILE *) context);
968 if (ret < 0) xmlIOErr(0, "fread()");
969 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000970}
971
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000972#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000973/**
974 * xmlFileWrite:
975 * @context: the I/O context
976 * @buffer: where to drop data
977 * @len: number of bytes to write
978 *
979 * Write @len bytes from @buffer to the I/O channel.
980 *
981 * Returns the number of bytes written
982 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000983static int
Owen Taylor3473f882001-02-23 17:55:21 +0000984xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000985 int items;
986
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200987 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +0000988 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000989 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000990 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000991 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000992 return(-1);
993 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000994 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000995}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000996#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000997
998/**
999 * xmlFileClose:
1000 * @context: the I/O context
1001 *
1002 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001003 *
1004 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001005 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001006int
Owen Taylor3473f882001-02-23 17:55:21 +00001007xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001008 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001009 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001010
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001011 if (context == NULL)
1012 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001013 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001014 if ((fil == stdout) || (fil == stderr)) {
1015 ret = fflush(fil);
1016 if (ret < 0)
1017 xmlIOErr(0, "fflush()");
1018 return(0);
1019 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001020 if (fil == stdin)
1021 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001022 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1023 if (ret < 0)
1024 xmlIOErr(0, "fclose()");
1025 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001026}
1027
1028/**
1029 * xmlFileFlush:
1030 * @context: the I/O context
1031 *
1032 * Flush an I/O channel
1033 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001034static int
Owen Taylor3473f882001-02-23 17:55:21 +00001035xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001036 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001037
1038 if (context == NULL)
1039 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001040 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1041 if (ret < 0)
1042 xmlIOErr(0, "fflush()");
1043 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001044}
1045
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001046#ifdef LIBXML_OUTPUT_ENABLED
1047/**
1048 * xmlBufferWrite:
1049 * @context: the xmlBuffer
1050 * @buffer: the data to write
1051 * @len: number of bytes to write
1052 *
1053 * Write @len bytes from @buffer to the xml buffer
1054 *
1055 * Returns the number of bytes written
1056 */
1057static int
1058xmlBufferWrite (void * context, const char * buffer, int len) {
1059 int ret;
1060
1061 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1062 if (ret != 0)
1063 return(-1);
1064 return(len);
1065}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001066#endif
1067
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001068#ifdef LIBXML_ZLIB_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001069/************************************************************************
1070 * *
1071 * I/O for compressed file accesses *
1072 * *
1073 ************************************************************************/
1074/**
1075 * xmlGzfileMatch:
1076 * @filename: the URI for matching
1077 *
1078 * input from compressed file test
1079 *
1080 * Returns 1 if matches, 0 otherwise
1081 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001082static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001083xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001084 return(1);
1085}
1086
1087/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001088 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001089 * @filename: the URI for matching
1090 *
1091 * input from compressed file open
1092 * if @filename is " " then the standard input is used
1093 *
1094 * Returns an I/O context or NULL in case of error
1095 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001096static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001097xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001098 const char *path = NULL;
1099 gzFile fd;
1100
1101 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001102 int duped_fd = dup(fileno(stdin));
1103 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001104 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001105 close(duped_fd); /* gzdOpen() does not close on failure */
1106 }
1107
Owen Taylor3473f882001-02-23 17:55:21 +00001108 return((void *) fd);
1109 }
1110
Daniel Veillardf4862f02002-09-10 11:13:43 +00001111 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001112#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001113 path = &filename[17];
1114#else
Owen Taylor3473f882001-02-23 17:55:21 +00001115 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001116#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001117 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001118#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001119 path = &filename[8];
1120#else
Owen Taylor3473f882001-02-23 17:55:21 +00001121 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001122#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001123 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001124 path = filename;
1125
1126 if (path == NULL)
1127 return(NULL);
1128 if (!xmlCheckFilename(path))
1129 return(NULL);
1130
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001131#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Nick Wellnhofer56723972017-10-09 15:35:32 +02001132 fd = xmlWrapGzOpenUtf8(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001133#else
Owen Taylor3473f882001-02-23 17:55:21 +00001134 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001135#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001136 return((void *) fd);
1137}
1138
1139/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001140 * xmlGzfileOpen:
1141 * @filename: the URI for matching
1142 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001143 * Wrapper around xmlGzfileOpen if the open fais, it will
1144 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001145 */
1146static void *
1147xmlGzfileOpen (const char *filename) {
1148 char *unescaped;
1149 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001150
1151 retval = xmlGzfileOpen_real(filename);
1152 if (retval == NULL) {
1153 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1154 if (unescaped != NULL) {
1155 retval = xmlGzfileOpen_real(unescaped);
1156 }
1157 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001158 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001159 return retval;
1160}
1161
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001162#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001163/**
Owen Taylor3473f882001-02-23 17:55:21 +00001164 * xmlGzfileOpenW:
1165 * @filename: the URI for matching
1166 * @compression: the compression factor (0 - 9 included)
1167 *
1168 * input from compressed file open
1169 * if @filename is " " then the standard input is used
1170 *
1171 * Returns an I/O context or NULL in case of error
1172 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001173static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001174xmlGzfileOpenW (const char *filename, int compression) {
1175 const char *path = NULL;
1176 char mode[15];
1177 gzFile fd;
1178
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001179 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001180 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001181 int duped_fd = dup(fileno(stdout));
1182 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001183 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001184 close(duped_fd); /* gzdOpen() does not close on failure */
1185 }
1186
Owen Taylor3473f882001-02-23 17:55:21 +00001187 return((void *) fd);
1188 }
1189
Daniel Veillardf4862f02002-09-10 11:13:43 +00001190 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001191#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001192 path = &filename[17];
1193#else
Owen Taylor3473f882001-02-23 17:55:21 +00001194 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001195#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001196 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001197#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001198 path = &filename[8];
1199#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001200 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001201#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001202 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001203 path = filename;
1204
1205 if (path == NULL)
1206 return(NULL);
1207
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001208#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Nick Wellnhofer56723972017-10-09 15:35:32 +02001209 fd = xmlWrapGzOpenUtf8(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001210#else
Owen Taylor3473f882001-02-23 17:55:21 +00001211 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001212#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001213 return((void *) fd);
1214}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001215#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001216
1217/**
1218 * xmlGzfileRead:
1219 * @context: the I/O context
1220 * @buffer: where to drop data
1221 * @len: number of bytes to write
1222 *
1223 * Read @len bytes to @buffer from the compressed I/O channel.
1224 *
Nick Wellnhofer5a0ae662017-06-17 23:20:38 +02001225 * Returns the number of bytes read.
Owen Taylor3473f882001-02-23 17:55:21 +00001226 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001227static int
Owen Taylor3473f882001-02-23 17:55:21 +00001228xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001229 int ret;
1230
1231 ret = gzread((gzFile) context, &buffer[0], len);
1232 if (ret < 0) xmlIOErr(0, "gzread()");
1233 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001234}
1235
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001236#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001237/**
1238 * xmlGzfileWrite:
1239 * @context: the I/O context
1240 * @buffer: where to drop data
1241 * @len: number of bytes to write
1242 *
1243 * Write @len bytes from @buffer to the compressed I/O channel.
1244 *
1245 * Returns the number of bytes written
1246 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001247static int
Owen Taylor3473f882001-02-23 17:55:21 +00001248xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001249 int ret;
1250
1251 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1252 if (ret < 0) xmlIOErr(0, "gzwrite()");
1253 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001254}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001255#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001256
1257/**
1258 * xmlGzfileClose:
1259 * @context: the I/O context
1260 *
1261 * Close a compressed I/O channel
1262 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001263static int
Owen Taylor3473f882001-02-23 17:55:21 +00001264xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001265 int ret;
1266
1267 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1268 if (ret < 0) xmlIOErr(0, "gzclose()");
1269 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001270}
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001271#endif /* LIBXML_ZLIB_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001272
Daniel Veillard18b89882015-11-03 15:46:29 +08001273#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001274/************************************************************************
1275 * *
1276 * I/O for compressed file accesses *
1277 * *
1278 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001279#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001280/**
1281 * xmlXzfileMatch:
1282 * @filename: the URI for matching
1283 *
1284 * input from compressed file test
1285 *
1286 * Returns 1 if matches, 0 otherwise
1287 */
1288static int
1289xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1290 return(1);
1291}
1292
1293/**
1294 * xmlXzFileOpen_real:
1295 * @filename: the URI for matching
1296 *
1297 * input from compressed file open
1298 * if @filename is " " then the standard input is used
1299 *
1300 * Returns an I/O context or NULL in case of error
1301 */
1302static void *
1303xmlXzfileOpen_real (const char *filename) {
1304 const char *path = NULL;
1305 xzFile fd;
1306
1307 if (!strcmp(filename, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001308 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001309 return((void *) fd);
1310 }
1311
1312 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1313 path = &filename[16];
1314 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1315 path = &filename[7];
1316 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1317 /* lots of generators seems to lazy to read RFC 1738 */
1318 path = &filename[5];
1319 } else
1320 path = filename;
1321
1322 if (path == NULL)
1323 return(NULL);
1324 if (!xmlCheckFilename(path))
1325 return(NULL);
1326
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001327 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001328 return((void *) fd);
1329}
1330
1331/**
1332 * xmlXzfileOpen:
1333 * @filename: the URI for matching
1334 *
1335 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1336 * version of @filename, if this fails fallback to @filename
1337 *
1338 * Returns a handler or NULL in case or failure
1339 */
1340static void *
1341xmlXzfileOpen (const char *filename) {
1342 char *unescaped;
1343 void *retval;
1344
1345 retval = xmlXzfileOpen_real(filename);
1346 if (retval == NULL) {
1347 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1348 if (unescaped != NULL) {
1349 retval = xmlXzfileOpen_real(unescaped);
1350 }
1351 xmlFree(unescaped);
1352 }
1353
1354 return retval;
1355}
1356
1357/**
1358 * xmlXzfileRead:
1359 * @context: the I/O context
1360 * @buffer: where to drop data
1361 * @len: number of bytes to write
1362 *
1363 * Read @len bytes to @buffer from the compressed I/O channel.
1364 *
1365 * Returns the number of bytes written
1366 */
1367static int
1368xmlXzfileRead (void * context, char * buffer, int len) {
1369 int ret;
1370
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001371 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001372 if (ret < 0) xmlIOErr(0, "xzread()");
1373 return(ret);
1374}
1375
1376/**
1377 * xmlXzfileClose:
1378 * @context: the I/O context
1379 *
1380 * Close a compressed I/O channel
1381 */
1382static int
1383xmlXzfileClose (void * context) {
1384 int ret;
1385
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001386 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001387 if (ret < 0) xmlIOErr(0, "xzclose()");
1388 return(ret);
1389}
Daniel Veillard18b89882015-11-03 15:46:29 +08001390#endif /* LIBXML_LZMA_ENABLED */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001391
Owen Taylor3473f882001-02-23 17:55:21 +00001392#ifdef LIBXML_HTTP_ENABLED
1393/************************************************************************
1394 * *
1395 * I/O for HTTP file accesses *
1396 * *
1397 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001398
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001399#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001400typedef struct xmlIOHTTPWriteCtxt_
1401{
1402 int compression;
1403
1404 char * uri;
1405
1406 void * doc_buff;
1407
1408} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1409
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001410#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001411
1412#define DFLT_WBITS ( -15 )
1413#define DFLT_MEM_LVL ( 8 )
1414#define GZ_MAGIC1 ( 0x1f )
1415#define GZ_MAGIC2 ( 0x8b )
1416#define LXML_ZLIB_OS_CODE ( 0x03 )
1417#define INIT_HTTP_BUFF_SIZE ( 32768 )
1418#define DFLT_ZLIB_RATIO ( 5 )
1419
1420/*
1421** Data structure and functions to work with sending compressed data
1422** via HTTP.
1423*/
1424
1425typedef struct xmlZMemBuff_
1426{
1427 unsigned long size;
1428 unsigned long crc;
1429
1430 unsigned char * zbuff;
1431 z_stream zctrl;
1432
1433} xmlZMemBuff, *xmlZMemBuffPtr;
1434
1435/**
1436 * append_reverse_ulong
1437 * @buff: Compressed memory buffer
1438 * @data: Unsigned long to append
1439 *
1440 * Append a unsigned long in reverse byte order to the end of the
1441 * memory buffer.
1442 */
1443static void
1444append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1445
1446 int idx;
1447
1448 if ( buff == NULL )
1449 return;
1450
1451 /*
1452 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001453 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001454 ** support 64 bit file sizes, this code would need to be patched
1455 ** as well.
1456 */
1457
1458 for ( idx = 0; idx < 4; idx++ ) {
1459 *buff->zctrl.next_out = ( data & 0xff );
1460 data >>= 8;
1461 buff->zctrl.next_out++;
1462 }
1463
1464 return;
1465}
1466
1467/**
1468 *
1469 * xmlFreeZMemBuff
1470 * @buff: The memory buffer context to clear
1471 *
1472 * Release all the resources associated with the compressed memory buffer.
1473 */
1474static void
1475xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001476
1477#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001478 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001479#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001480
1481 if ( buff == NULL )
1482 return;
1483
1484 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001485#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001486 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001487 if ( z_err != Z_OK )
1488 xmlGenericError( xmlGenericErrorContext,
1489 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1490 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001491#else
1492 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001493#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001494
1495 xmlFree( buff );
1496 return;
1497}
1498
1499/**
1500 * xmlCreateZMemBuff
1501 *@compression: Compression value to use
1502 *
1503 * Create a memory buffer to hold the compressed XML document. The
1504 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001505 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001506 * write the document to disk. The code for the header/trailer data to
1507 * the compression is plagiarized from the zlib source files.
1508 */
1509static void *
1510xmlCreateZMemBuff( int compression ) {
1511
1512 int z_err;
1513 int hdr_lgth;
1514 xmlZMemBuffPtr buff = NULL;
1515
1516 if ( ( compression < 1 ) || ( compression > 9 ) )
1517 return ( NULL );
1518
1519 /* Create the control and data areas */
1520
1521 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1522 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001523 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001524 return ( NULL );
1525 }
1526
1527 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1528 buff->size = INIT_HTTP_BUFF_SIZE;
1529 buff->zbuff = xmlMalloc( buff->size );
1530 if ( buff->zbuff == NULL ) {
1531 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001532 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001533 return ( NULL );
1534 }
1535
1536 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1537 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1538 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001539 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001540 xmlFreeZMemBuff( buff );
1541 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001542 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001543 "xmlCreateZMemBuff: %s %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001544 "Error initializing compression context. ZLIB error:",
1545 z_err );
1546 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001547 return ( NULL );
1548 }
1549
1550 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001551 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001552 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1553 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001554 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001555 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1556 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1557 buff->zctrl.avail_out = buff->size - hdr_lgth;
1558
1559 return ( buff );
1560}
1561
1562/**
1563 * xmlZMemBuffExtend
1564 * @buff: Buffer used to compress and consolidate data.
1565 * @ext_amt: Number of bytes to extend the buffer.
1566 *
1567 * Extend the internal buffer used to store the compressed data by the
1568 * specified amount.
1569 *
1570 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1571 * the original buffer still exists at the original size.
1572 */
1573static int
1574xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1575
1576 int rc = -1;
1577 size_t new_size;
1578 size_t cur_used;
1579
1580 unsigned char * tmp_ptr = NULL;
1581
1582 if ( buff == NULL )
1583 return ( -1 );
1584
1585 else if ( ext_amt == 0 )
1586 return ( 0 );
1587
1588 cur_used = buff->zctrl.next_out - buff->zbuff;
1589 new_size = buff->size + ext_amt;
1590
1591#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001592 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001593 xmlGenericError( xmlGenericErrorContext,
1594 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1595 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001596 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001597 (cur_used - new_size ) );
1598#endif
1599
1600 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1601 if ( tmp_ptr != NULL ) {
1602 rc = 0;
1603 buff->size = new_size;
1604 buff->zbuff = tmp_ptr;
1605 buff->zctrl.next_out = tmp_ptr + cur_used;
1606 buff->zctrl.avail_out = new_size - cur_used;
1607 }
1608 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001609 xmlChar msg[500];
1610 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001611 "xmlZMemBuffExtend: %s %lu bytes.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001612 "Allocation failure extending output buffer to",
Nick Wellnhoferc2545cb2016-08-22 11:44:18 +02001613 (unsigned long) new_size );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001614 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001615 }
1616
1617 return ( rc );
1618}
1619
1620/**
1621 * xmlZMemBuffAppend
1622 * @buff: Buffer used to compress and consolidate data
1623 * @src: Uncompressed source content to append to buffer
1624 * @len: Length of source data to append to buffer
1625 *
1626 * Compress and append data to the internal buffer. The data buffer
1627 * will be expanded if needed to store the additional data.
1628 *
1629 * Returns the number of bytes appended to the buffer or -1 on error.
1630 */
1631static int
1632xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1633
1634 int z_err;
1635 size_t min_accept;
1636
1637 if ( ( buff == NULL ) || ( src == NULL ) )
1638 return ( -1 );
1639
1640 buff->zctrl.avail_in = len;
1641 buff->zctrl.next_in = (unsigned char *)src;
1642 while ( buff->zctrl.avail_in > 0 ) {
1643 /*
1644 ** Extend the buffer prior to deflate call if a reasonable amount
1645 ** of output buffer space is not available.
1646 */
1647 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1648 if ( buff->zctrl.avail_out <= min_accept ) {
1649 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1650 return ( -1 );
1651 }
1652
1653 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1654 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001655 xmlChar msg[500];
1656 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001657 "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001658 "Compression error while appending",
1659 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001660 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001661 return ( -1 );
1662 }
1663 }
1664
1665 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1666
1667 return ( len );
1668}
1669
1670/**
1671 * xmlZMemBuffGetContent
1672 * @buff: Compressed memory content buffer
1673 * @data_ref: Pointer reference to point to compressed content
1674 *
1675 * Flushes the compression buffers, appends gzip file trailers and
1676 * returns the compressed content and length of the compressed data.
1677 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1678 *
1679 * Returns the length of the compressed data or -1 on error.
1680 */
1681static int
1682xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1683
1684 int zlgth = -1;
1685 int z_err;
1686
1687 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1688 return ( -1 );
1689
1690 /* Need to loop until compression output buffers are flushed */
1691
1692 do
1693 {
1694 z_err = deflate( &buff->zctrl, Z_FINISH );
1695 if ( z_err == Z_OK ) {
1696 /* In this case Z_OK means more buffer space needed */
1697
1698 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1699 return ( -1 );
1700 }
1701 }
1702 while ( z_err == Z_OK );
1703
1704 /* If the compression state is not Z_STREAM_END, some error occurred */
1705
1706 if ( z_err == Z_STREAM_END ) {
1707
1708 /* Need to append the gzip data trailer */
1709
1710 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1711 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1712 return ( -1 );
1713 }
1714
1715 /*
1716 ** For whatever reason, the CRC and length data are pushed out
1717 ** in reverse byte order. So a memcpy can't be used here.
1718 */
1719
1720 append_reverse_ulong( buff, buff->crc );
1721 append_reverse_ulong( buff, buff->zctrl.total_in );
1722
1723 zlgth = buff->zctrl.next_out - buff->zbuff;
1724 *data_ref = (char *)buff->zbuff;
1725 }
1726
Daniel Veillard05d987b2003-10-08 11:54:57 +00001727 else {
1728 xmlChar msg[500];
1729 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001730 "xmlZMemBuffGetContent: %s - %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001731 "Error flushing zlib buffers. Error code", z_err );
1732 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1733 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001734
Daniel Veillardf012a642001-07-23 19:10:52 +00001735 return ( zlgth );
1736}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001737#endif /* LIBXML_OUTPUT_ENABLED */
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001738#endif /* LIBXML_ZLIB_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001739
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001740#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001741/**
1742 * xmlFreeHTTPWriteCtxt
1743 * @ctxt: Context to cleanup
1744 *
1745 * Free allocated memory and reclaim system resources.
1746 *
1747 * No return value.
1748 */
1749static void
1750xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1751{
1752 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001753 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001754
1755 if ( ctxt->doc_buff != NULL ) {
1756
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001757#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001758 if ( ctxt->compression > 0 ) {
1759 xmlFreeZMemBuff( ctxt->doc_buff );
1760 }
1761 else
1762#endif
1763 {
1764 xmlOutputBufferClose( ctxt->doc_buff );
1765 }
1766 }
1767
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001768 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001769 return;
1770}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001771#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001772
1773
Owen Taylor3473f882001-02-23 17:55:21 +00001774/**
1775 * xmlIOHTTPMatch:
1776 * @filename: the URI for matching
1777 *
1778 * check if the URI matches an HTTP one
1779 *
1780 * Returns 1 if matches, 0 otherwise
1781 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001782int
Owen Taylor3473f882001-02-23 17:55:21 +00001783xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001784 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001785 return(1);
1786 return(0);
1787}
1788
1789/**
1790 * xmlIOHTTPOpen:
1791 * @filename: the URI for matching
1792 *
1793 * open an HTTP I/O channel
1794 *
1795 * Returns an I/O context or NULL in case of error
1796 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001797void *
Owen Taylor3473f882001-02-23 17:55:21 +00001798xmlIOHTTPOpen (const char *filename) {
1799 return(xmlNanoHTTPOpen(filename, NULL));
1800}
1801
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001802#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001803/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001804 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001805 * @post_uri: The destination URI for the document
1806 * @compression: The compression desired for the document.
1807 *
1808 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1809 * request. Non-static as is called from the output buffer creation routine.
1810 *
1811 * Returns an I/O context or NULL in case of error.
1812 */
1813
1814void *
Nick Wellnhofer81c01ee2017-06-17 14:12:53 +02001815xmlIOHTTPOpenW(const char *post_uri, int compression ATTRIBUTE_UNUSED)
Daniel Veillard572577e2002-01-18 16:23:55 +00001816{
Daniel Veillardf012a642001-07-23 19:10:52 +00001817
Daniel Veillard572577e2002-01-18 16:23:55 +00001818 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001819
Daniel Veillard572577e2002-01-18 16:23:55 +00001820 if (post_uri == NULL)
1821 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001822
Daniel Veillard572577e2002-01-18 16:23:55 +00001823 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1824 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001825 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001826 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001827 }
1828
Daniel Veillard572577e2002-01-18 16:23:55 +00001829 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001830
Daniel Veillard572577e2002-01-18 16:23:55 +00001831 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1832 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001833 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001834 xmlFreeHTTPWriteCtxt(ctxt);
1835 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001836 }
1837
1838 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001839 * ** Since the document length is required for an HTTP post,
1840 * ** need to put the document into a buffer. A memory buffer
1841 * ** is being used to avoid pushing the data to disk and back.
1842 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001843
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001844#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard572577e2002-01-18 16:23:55 +00001845 if ((compression > 0) && (compression <= 9)) {
1846
1847 ctxt->compression = compression;
1848 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1849 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001850#endif
1851 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001852 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001853
Daniel Veillardda3fee42008-09-01 13:08:57 +00001854 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001855 }
1856
Daniel Veillard572577e2002-01-18 16:23:55 +00001857 if (ctxt->doc_buff == NULL) {
1858 xmlFreeHTTPWriteCtxt(ctxt);
1859 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001860 }
1861
Daniel Veillard572577e2002-01-18 16:23:55 +00001862 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001863}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001864#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001865
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001866#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001867/**
1868 * xmlIOHTTPDfltOpenW
1869 * @post_uri: The destination URI for this document.
1870 *
1871 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1872 * HTTP post command. This function should generally not be used as
1873 * the open callback is short circuited in xmlOutputBufferCreateFile.
1874 *
1875 * Returns a pointer to the new IO context.
1876 */
1877static void *
1878xmlIOHTTPDfltOpenW( const char * post_uri ) {
1879 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1880}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001881#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001882
1883/**
Owen Taylor3473f882001-02-23 17:55:21 +00001884 * xmlIOHTTPRead:
1885 * @context: the I/O context
1886 * @buffer: where to drop data
1887 * @len: number of bytes to write
1888 *
1889 * Read @len bytes to @buffer from the I/O channel.
1890 *
1891 * Returns the number of bytes written
1892 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001893int
Owen Taylor3473f882001-02-23 17:55:21 +00001894xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001895 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001896 return(xmlNanoHTTPRead(context, &buffer[0], len));
1897}
1898
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001899#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001900/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001901 * xmlIOHTTPWrite
1902 * @context: previously opened writing context
1903 * @buffer: data to output to temporary buffer
1904 * @len: bytes to output
1905 *
1906 * Collect data from memory buffer into a temporary file for later
1907 * processing.
1908 *
1909 * Returns number of bytes written.
1910 */
1911
1912static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001913xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001914
1915 xmlIOHTTPWriteCtxtPtr ctxt = context;
1916
1917 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1918 return ( -1 );
1919
1920 if ( len > 0 ) {
1921
1922 /* Use gzwrite or fwrite as previously setup in the open call */
1923
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001924#ifdef LIBXML_ZLIB_ENABLED
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001925 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001926 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1927
1928 else
1929#endif
1930 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1931
1932 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001933 xmlChar msg[500];
1934 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001935 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001936 "Error appending to internal buffer.",
1937 "Error sending document to URI",
1938 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001939 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001940 }
1941 }
1942
1943 return ( len );
1944}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001945#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001946
1947
1948/**
Owen Taylor3473f882001-02-23 17:55:21 +00001949 * xmlIOHTTPClose:
1950 * @context: the I/O context
1951 *
1952 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001953 *
1954 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001955 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001956int
Owen Taylor3473f882001-02-23 17:55:21 +00001957xmlIOHTTPClose (void * context) {
1958 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001959 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001960}
Daniel Veillardf012a642001-07-23 19:10:52 +00001961
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001962#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001963/**
1964 * xmlIOHTTCloseWrite
1965 * @context: The I/O context
1966 * @http_mthd: The HTTP method to be used when sending the data
1967 *
1968 * Close the transmit HTTP I/O channel and actually send the data.
1969 */
1970static int
1971xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1972
1973 int close_rc = -1;
1974 int http_rtn = 0;
1975 int content_lgth = 0;
1976 xmlIOHTTPWriteCtxtPtr ctxt = context;
1977
1978 char * http_content = NULL;
1979 char * content_encoding = NULL;
1980 char * content_type = (char *) "text/xml";
1981 void * http_ctxt = NULL;
1982
1983 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1984 return ( -1 );
1985
1986 /* Retrieve the content from the appropriate buffer */
1987
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01001988#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001989
1990 if ( ctxt->compression > 0 ) {
1991 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1992 content_encoding = (char *) "Content-Encoding: gzip";
1993 }
1994 else
1995#endif
1996 {
1997 /* Pull the data out of the memory output buffer */
1998
1999 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002000 http_content = (char *) xmlBufContent(dctxt->buffer);
2001 content_lgth = xmlBufUse(dctxt->buffer);
Daniel Veillardf012a642001-07-23 19:10:52 +00002002 }
2003
2004 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002005 xmlChar msg[500];
2006 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08002007 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00002008 "Error retrieving content.\nUnable to",
2009 http_mthd, "data to URI", ctxt->uri );
2010 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002011 }
2012
2013 else {
2014
2015 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002016 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00002017 content_lgth );
2018
2019 if ( http_ctxt != NULL ) {
2020#ifdef DEBUG_HTTP
2021 /* If testing/debugging - dump reply with request content */
2022
2023 FILE * tst_file = NULL;
2024 char buffer[ 4096 ];
2025 char * dump_name = NULL;
2026 int avail;
2027
2028 xmlGenericError( xmlGenericErrorContext,
2029 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2030 http_mthd, ctxt->uri,
2031 xmlNanoHTTPReturnCode( http_ctxt ) );
2032
2033 /*
2034 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002035 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002036 ** standard error context.
2037 */
2038
2039 dump_name = tempnam( NULL, "lxml" );
2040 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002041 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002042
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002043 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002044 if ( tst_file != NULL ) {
2045 xmlGenericError( xmlGenericErrorContext,
2046 "Transmitted content saved in file: %s\n", buffer );
2047
2048 fwrite( http_content, sizeof( char ),
2049 content_lgth, tst_file );
2050 fclose( tst_file );
2051 }
2052
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002053 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002054 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002055 if ( tst_file != NULL ) {
2056 xmlGenericError( xmlGenericErrorContext,
2057 "Reply content saved in file: %s\n", buffer );
2058
2059
2060 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2061 buffer, sizeof( buffer ) )) > 0 ) {
2062
2063 fwrite( buffer, sizeof( char ), avail, tst_file );
2064 }
2065
2066 fclose( tst_file );
2067 }
2068
2069 free( dump_name );
2070 }
2071#endif /* DEBUG_HTTP */
2072
2073 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2074 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2075 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002076 else {
2077 xmlChar msg[500];
2078 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08002079 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002080 http_mthd, content_lgth,
2081 "bytes to URI", ctxt->uri,
2082 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002083 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2084 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002085
2086 xmlNanoHTTPClose( http_ctxt );
2087 xmlFree( content_type );
2088 }
2089 }
2090
2091 /* Final cleanups */
2092
2093 xmlFreeHTTPWriteCtxt( ctxt );
2094
2095 return ( close_rc );
2096}
2097
2098/**
2099 * xmlIOHTTPClosePut
2100 *
2101 * @context: The I/O context
2102 *
2103 * Close the transmit HTTP I/O channel and actually send data using a PUT
2104 * HTTP method.
2105 */
2106static int
2107xmlIOHTTPClosePut( void * ctxt ) {
2108 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2109}
2110
2111
2112/**
2113 * xmlIOHTTPClosePost
2114 *
2115 * @context: The I/O context
2116 *
2117 * Close the transmit HTTP I/O channel and actually send data using a POST
2118 * HTTP method.
2119 */
2120static int
2121xmlIOHTTPClosePost( void * ctxt ) {
2122 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2123}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002124#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002125
Owen Taylor3473f882001-02-23 17:55:21 +00002126#endif /* LIBXML_HTTP_ENABLED */
2127
2128#ifdef LIBXML_FTP_ENABLED
2129/************************************************************************
2130 * *
2131 * I/O for FTP file accesses *
2132 * *
2133 ************************************************************************/
2134/**
2135 * xmlIOFTPMatch:
2136 * @filename: the URI for matching
2137 *
2138 * check if the URI matches an FTP one
2139 *
2140 * Returns 1 if matches, 0 otherwise
2141 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002142int
Owen Taylor3473f882001-02-23 17:55:21 +00002143xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002144 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002145 return(1);
2146 return(0);
2147}
2148
2149/**
2150 * xmlIOFTPOpen:
2151 * @filename: the URI for matching
2152 *
2153 * open an FTP I/O channel
2154 *
2155 * Returns an I/O context or NULL in case of error
2156 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002157void *
Owen Taylor3473f882001-02-23 17:55:21 +00002158xmlIOFTPOpen (const char *filename) {
2159 return(xmlNanoFTPOpen(filename));
2160}
2161
2162/**
2163 * xmlIOFTPRead:
2164 * @context: the I/O context
2165 * @buffer: where to drop data
2166 * @len: number of bytes to write
2167 *
2168 * Read @len bytes to @buffer from the I/O channel.
2169 *
2170 * Returns the number of bytes written
2171 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002172int
Owen Taylor3473f882001-02-23 17:55:21 +00002173xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002174 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002175 return(xmlNanoFTPRead(context, &buffer[0], len));
2176}
2177
2178/**
2179 * xmlIOFTPClose:
2180 * @context: the I/O context
2181 *
2182 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002183 *
2184 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002185 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002186int
Owen Taylor3473f882001-02-23 17:55:21 +00002187xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002188 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002189}
2190#endif /* LIBXML_FTP_ENABLED */
2191
2192
2193/**
2194 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002195 * @matchFunc: the xmlInputMatchCallback
2196 * @openFunc: the xmlInputOpenCallback
2197 * @readFunc: the xmlInputReadCallback
2198 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002199 *
2200 * Register a new set of I/O callback for handling parser input.
2201 *
2202 * Returns the registered handler number or -1 in case of error
2203 */
2204int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002205xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2206 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2207 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002208 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2209 return(-1);
2210 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002211 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2212 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2213 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2214 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002215 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002216 return(xmlInputCallbackNr++);
2217}
2218
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002219#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002220/**
2221 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002222 * @matchFunc: the xmlOutputMatchCallback
2223 * @openFunc: the xmlOutputOpenCallback
2224 * @writeFunc: the xmlOutputWriteCallback
2225 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002226 *
2227 * Register a new set of I/O callback for handling output.
2228 *
2229 * Returns the registered handler number or -1 in case of error
2230 */
2231int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002232xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2233 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2234 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002235 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002236 return(-1);
2237 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002238 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2239 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2240 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2241 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002242 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002243 return(xmlOutputCallbackNr++);
2244}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002245#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002246
2247/**
2248 * xmlRegisterDefaultInputCallbacks:
2249 *
2250 * Registers the default compiled-in I/O handlers.
2251 */
2252void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002253xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002254 if (xmlInputCallbackInitialized)
2255 return;
2256
2257 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2258 xmlFileRead, xmlFileClose);
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002259#ifdef LIBXML_ZLIB_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002260 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2261 xmlGzfileRead, xmlGzfileClose);
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002262#endif /* LIBXML_ZLIB_ENABLED */
Daniel Veillard18b89882015-11-03 15:46:29 +08002263#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002264 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2265 xmlXzfileRead, xmlXzfileClose);
Daniel Veillard18b89882015-11-03 15:46:29 +08002266#endif /* LIBXML_LZMA_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002267
2268#ifdef LIBXML_HTTP_ENABLED
2269 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2270 xmlIOHTTPRead, xmlIOHTTPClose);
2271#endif /* LIBXML_HTTP_ENABLED */
2272
2273#ifdef LIBXML_FTP_ENABLED
2274 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2275 xmlIOFTPRead, xmlIOFTPClose);
2276#endif /* LIBXML_FTP_ENABLED */
2277 xmlInputCallbackInitialized = 1;
2278}
2279
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002280#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002281/**
2282 * xmlRegisterDefaultOutputCallbacks:
2283 *
2284 * Registers the default compiled-in I/O handlers.
2285 */
2286void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002287xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002288 if (xmlOutputCallbackInitialized)
2289 return;
2290
2291 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2292 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002293
2294#ifdef LIBXML_HTTP_ENABLED
2295 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2296 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2297#endif
2298
Owen Taylor3473f882001-02-23 17:55:21 +00002299/*********************************
2300 No way a-priori to distinguish between gzipped files from
2301 uncompressed ones except opening if existing then closing
2302 and saving with same compression ratio ... a pain.
2303
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002304#ifdef LIBXML_ZLIB_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002305 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2306 xmlGzfileWrite, xmlGzfileClose);
2307#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002308
2309 Nor FTP PUT ....
2310#ifdef LIBXML_FTP_ENABLED
2311 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2312 xmlIOFTPWrite, xmlIOFTPClose);
2313#endif
2314 **********************************/
2315 xmlOutputCallbackInitialized = 1;
2316}
2317
Daniel Veillardf012a642001-07-23 19:10:52 +00002318#ifdef LIBXML_HTTP_ENABLED
2319/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002320 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002321 *
2322 * By default, libxml submits HTTP output requests using the "PUT" method.
2323 * Calling this method changes the HTTP output method to use the "POST"
2324 * method instead.
2325 *
2326 */
2327void
2328xmlRegisterHTTPPostCallbacks( void ) {
2329
2330 /* Register defaults if not done previously */
2331
2332 if ( xmlOutputCallbackInitialized == 0 )
2333 xmlRegisterDefaultOutputCallbacks( );
2334
2335 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2336 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2337 return;
2338}
2339#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002340#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002341
Owen Taylor3473f882001-02-23 17:55:21 +00002342/**
2343 * xmlAllocParserInputBuffer:
2344 * @enc: the charset encoding if known
2345 *
2346 * Create a buffered parser input for progressive parsing
2347 *
2348 * Returns the new parser input or NULL
2349 */
2350xmlParserInputBufferPtr
2351xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2352 xmlParserInputBufferPtr ret;
2353
2354 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2355 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002356 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002357 return(NULL);
2358 }
2359 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002360 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002361 if (ret->buffer == NULL) {
2362 xmlFree(ret);
2363 return(NULL);
2364 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002365 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Owen Taylor3473f882001-02-23 17:55:21 +00002366 ret->encoder = xmlGetCharEncodingHandler(enc);
2367 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002368 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002369 else
2370 ret->raw = NULL;
2371 ret->readcallback = NULL;
2372 ret->closecallback = NULL;
2373 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002374 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002375 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002376
2377 return(ret);
2378}
2379
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002380#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002381/**
2382 * xmlAllocOutputBuffer:
2383 * @encoder: the encoding converter or NULL
2384 *
2385 * Create a buffered parser output
2386 *
2387 * Returns the new parser output or NULL
2388 */
2389xmlOutputBufferPtr
2390xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2391 xmlOutputBufferPtr ret;
2392
2393 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2394 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002395 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002396 return(NULL);
2397 }
2398 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002399 ret->buffer = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00002400 if (ret->buffer == NULL) {
2401 xmlFree(ret);
2402 return(NULL);
2403 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002404
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002405 /* try to avoid a performance problem with Windows realloc() */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002406 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2407 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002408
Daniel Veillardda3fee42008-09-01 13:08:57 +00002409 ret->encoder = encoder;
2410 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002411 ret->conv = xmlBufCreateSize(4000);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002412 if (ret->conv == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002413 xmlBufFree(ret->buffer);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002414 xmlFree(ret);
2415 return(NULL);
2416 }
2417
2418 /*
2419 * This call is designed to initiate the encoder state
2420 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002421 xmlCharEncOutput(ret, 1);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002422 } else
2423 ret->conv = NULL;
2424 ret->writecallback = NULL;
2425 ret->closecallback = NULL;
2426 ret->context = NULL;
2427 ret->written = 0;
2428
2429 return(ret);
2430}
2431
2432/**
2433 * xmlAllocOutputBufferInternal:
2434 * @encoder: the encoding converter or NULL
2435 *
2436 * Create a buffered parser output
2437 *
2438 * Returns the new parser output or NULL
2439 */
2440xmlOutputBufferPtr
2441xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2442 xmlOutputBufferPtr ret;
2443
2444 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2445 if (ret == NULL) {
2446 xmlIOErrMemory("creating output buffer");
2447 return(NULL);
2448 }
2449 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002450 ret->buffer = xmlBufCreate();
Daniel Veillardda3fee42008-09-01 13:08:57 +00002451 if (ret->buffer == NULL) {
2452 xmlFree(ret);
2453 return(NULL);
2454 }
2455
2456
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002457 /*
2458 * For conversion buffers we use the special IO handling
2459 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002460 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002461
Owen Taylor3473f882001-02-23 17:55:21 +00002462 ret->encoder = encoder;
2463 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002464 ret->conv = xmlBufCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002465 if (ret->conv == NULL) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07002466 xmlBufFree(ret->buffer);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002467 xmlFree(ret);
2468 return(NULL);
2469 }
2470
Owen Taylor3473f882001-02-23 17:55:21 +00002471 /*
2472 * This call is designed to initiate the encoder state
2473 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002474 xmlCharEncOutput(ret, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002475 } else
2476 ret->conv = NULL;
2477 ret->writecallback = NULL;
2478 ret->closecallback = NULL;
2479 ret->context = NULL;
2480 ret->written = 0;
2481
2482 return(ret);
2483}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002484
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002485#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002486
2487/**
2488 * xmlFreeParserInputBuffer:
2489 * @in: a buffered parser input
2490 *
2491 * Free up the memory used by a buffered parser input
2492 */
2493void
2494xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002495 if (in == NULL) return;
2496
Owen Taylor3473f882001-02-23 17:55:21 +00002497 if (in->raw) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002498 xmlBufFree(in->raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002499 in->raw = NULL;
2500 }
2501 if (in->encoder != NULL) {
2502 xmlCharEncCloseFunc(in->encoder);
2503 }
2504 if (in->closecallback != NULL) {
2505 in->closecallback(in->context);
2506 }
2507 if (in->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002508 xmlBufFree(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00002509 in->buffer = NULL;
2510 }
2511
Owen Taylor3473f882001-02-23 17:55:21 +00002512 xmlFree(in);
2513}
2514
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002515#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002516/**
2517 * xmlOutputBufferClose:
2518 * @out: a buffered output
2519 *
2520 * flushes and close the output I/O channel
2521 * and free up all the associated resources
2522 *
2523 * Returns the number of byte written or -1 in case of error.
2524 */
2525int
Daniel Veillard828ce832003-10-08 19:19:10 +00002526xmlOutputBufferClose(xmlOutputBufferPtr out)
2527{
Owen Taylor3473f882001-02-23 17:55:21 +00002528 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002529 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002530
2531 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002532 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002533 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002534 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002535 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002536 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002537 }
2538 written = out->written;
2539 if (out->conv) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002540 xmlBufFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002541 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002542 }
2543 if (out->encoder != NULL) {
2544 xmlCharEncCloseFunc(out->encoder);
2545 }
2546 if (out->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002547 xmlBufFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002548 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002549 }
2550
Daniel Veillard828ce832003-10-08 19:19:10 +00002551 if (out->error)
2552 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002553 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002554 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002555}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002556#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002557
Daniel Veillard1b243b42004-06-08 10:16:42 +00002558xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002559__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002560 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002561 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002562 void *context = NULL;
2563
2564 if (xmlInputCallbackInitialized == 0)
2565 xmlRegisterDefaultInputCallbacks();
2566
2567 if (URI == NULL) return(NULL);
2568
2569 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002570 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002571 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002572 */
2573 if (context == NULL) {
2574 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2575 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2576 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002577 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002578 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002579 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002580 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002581 }
Owen Taylor3473f882001-02-23 17:55:21 +00002582 }
2583 }
2584 if (context == NULL) {
2585 return(NULL);
2586 }
2587
2588 /*
2589 * Allocate the Input buffer front-end.
2590 */
2591 ret = xmlAllocParserInputBuffer(enc);
2592 if (ret != NULL) {
2593 ret->context = context;
2594 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2595 ret->closecallback = xmlInputCallbackTable[i].closecallback;
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002596#ifdef LIBXML_ZLIB_ENABLED
William M. Brackc5cbf992003-10-29 22:15:13 +00002597 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2598 (strcmp(URI, "-") != 0)) {
Mark Adlera7e79f22010-01-19 16:28:48 +01002599#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2600 ret->compressed = !gzdirect(context);
2601#else
William M. Brackc07329e2003-09-08 01:57:30 +00002602 if (((z_stream *)context)->avail_in > 4) {
2603 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002604 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002605 if (gzread(context, buff4, 4) == 4) {
2606 if (strncmp(buff4, cptr, 4) == 0)
2607 ret->compressed = 0;
2608 else
2609 ret->compressed = 1;
2610 gzrewind(context);
2611 }
2612 }
Mark Adlera7e79f22010-01-19 16:28:48 +01002613#endif
William M. Brackc07329e2003-09-08 01:57:30 +00002614 }
2615#endif
Daniel Veillard18b89882015-11-03 15:46:29 +08002616#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08002617 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2618 (strcmp(URI, "-") != 0)) {
2619 ret->compressed = __libxml2_xzcompressed(context);
2620 }
2621#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002622 }
William M. Brack42331a92004-07-29 07:07:16 +00002623 else
2624 xmlInputCallbackTable[i].closecallback (context);
2625
Owen Taylor3473f882001-02-23 17:55:21 +00002626 return(ret);
2627}
2628
2629/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002630 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002631 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002632 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002633 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002634 * Create a buffered parser input for the progressive parsing of a file
2635 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002636 * Automatic support for ZLIB/Compress compressed document is provided
2637 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002638 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002639 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002640 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002641 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002642xmlParserInputBufferPtr
2643xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2644 if ((xmlParserInputBufferCreateFilenameValue)) {
2645 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2646 }
2647 return __xmlParserInputBufferCreateFilename(URI, enc);
2648}
2649
2650#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002651xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002652__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002653 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002654 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002655 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002656 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002657 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002658 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002659 char *unescaped = NULL;
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002660#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard966a31e2004-05-09 02:58:44 +00002661 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002662#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002663
Owen Taylor3473f882001-02-23 17:55:21 +00002664 if (xmlOutputCallbackInitialized == 0)
2665 xmlRegisterDefaultOutputCallbacks();
2666
2667 if (URI == NULL) return(NULL);
2668
Daniel Veillard966a31e2004-05-09 02:58:44 +00002669 puri = xmlParseURI(URI);
2670 if (puri != NULL) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002671#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard18a65092004-05-11 15:57:42 +00002672 if ((puri->scheme != NULL) &&
2673 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002674 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002675#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002676 /*
2677 * try to limit the damages of the URI unescaping code.
2678 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002679 if ((puri->scheme == NULL) ||
2680 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002681 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2682 xmlFreeURI(puri);
2683 }
Owen Taylor3473f882001-02-23 17:55:21 +00002684
2685 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002686 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002687 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002688 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002689 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002690 if (unescaped != NULL) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002691#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard966a31e2004-05-09 02:58:44 +00002692 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002693 context = xmlGzfileOpenW(unescaped, compression);
2694 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002695 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002696 if (ret != NULL) {
2697 ret->context = context;
2698 ret->writecallback = xmlGzfileWrite;
2699 ret->closecallback = xmlGzfileClose;
2700 }
2701 xmlFree(unescaped);
2702 return(ret);
2703 }
2704 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002705#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002706 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2707 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2708 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002709#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002710 /* Need to pass compression parameter into HTTP open calls */
2711 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2712 context = xmlIOHTTPOpenW(unescaped, compression);
2713 else
2714#endif
2715 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2716 if (context != NULL)
2717 break;
2718 }
2719 }
2720 xmlFree(unescaped);
2721 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002722
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002723 /*
2724 * If this failed try with a non-escaped URI this may be a strange
2725 * filename
2726 */
2727 if (context == NULL) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002728#ifdef LIBXML_ZLIB_ENABLED
Daniel Veillard966a31e2004-05-09 02:58:44 +00002729 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002730 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002731 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002732 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002733 if (ret != NULL) {
2734 ret->context = context;
2735 ret->writecallback = xmlGzfileWrite;
2736 ret->closecallback = xmlGzfileClose;
2737 }
Elliott Hughesecdab2a2022-02-23 14:33:50 -08002738 else
2739 xmlGzfileClose(context);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002740 return(ret);
2741 }
2742 }
2743#endif
2744 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2745 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002746 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Nick Wellnhofercb5541c2017-11-13 17:08:38 +01002747#if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002748 /* Need to pass compression parameter into HTTP open calls */
2749 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2750 context = xmlIOHTTPOpenW(URI, compression);
2751 else
2752#endif
2753 context = xmlOutputCallbackTable[i].opencallback(URI);
2754 if (context != NULL)
2755 break;
2756 }
Owen Taylor3473f882001-02-23 17:55:21 +00002757 }
2758 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002759
Owen Taylor3473f882001-02-23 17:55:21 +00002760 if (context == NULL) {
2761 return(NULL);
2762 }
2763
2764 /*
2765 * Allocate the Output buffer front-end.
2766 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002767 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002768 if (ret != NULL) {
2769 ret->context = context;
2770 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2771 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2772 }
2773 return(ret);
2774}
Daniel Veillard0335a842004-06-02 16:18:40 +00002775
2776/**
2777 * xmlOutputBufferCreateFilename:
2778 * @URI: a C string containing the URI or filename
2779 * @encoder: the encoding converter or NULL
2780 * @compression: the compression ration (0 none, 9 max).
2781 *
2782 * Create a buffered output for the progressive saving of a file
2783 * If filename is "-' then we use stdout as the output.
2784 * Automatic support for ZLIB/Compress compressed document is provided
2785 * by default if found at compile-time.
2786 * TODO: currently if compression is set, the library only support
2787 * writing to a local file.
2788 *
2789 * Returns the new output or NULL
2790 */
2791xmlOutputBufferPtr
2792xmlOutputBufferCreateFilename(const char *URI,
2793 xmlCharEncodingHandlerPtr encoder,
2794 int compression ATTRIBUTE_UNUSED) {
2795 if ((xmlOutputBufferCreateFilenameValue)) {
2796 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2797 }
2798 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2799}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002800#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002801
2802/**
2803 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002804 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002805 * @enc: the charset encoding if known
2806 *
2807 * Create a buffered parser input for the progressive parsing of a FILE *
2808 * buffered C I/O
2809 *
2810 * Returns the new parser input or NULL
2811 */
2812xmlParserInputBufferPtr
2813xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2814 xmlParserInputBufferPtr ret;
2815
2816 if (xmlInputCallbackInitialized == 0)
2817 xmlRegisterDefaultInputCallbacks();
2818
2819 if (file == NULL) return(NULL);
2820
2821 ret = xmlAllocParserInputBuffer(enc);
2822 if (ret != NULL) {
2823 ret->context = file;
2824 ret->readcallback = xmlFileRead;
2825 ret->closecallback = xmlFileFlush;
2826 }
2827
2828 return(ret);
2829}
2830
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002831#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002832/**
2833 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002834 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002835 * @encoder: the encoding converter or NULL
2836 *
2837 * Create a buffered output for the progressive saving to a FILE *
2838 * buffered C I/O
2839 *
2840 * Returns the new parser output or NULL
2841 */
2842xmlOutputBufferPtr
2843xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2844 xmlOutputBufferPtr ret;
2845
2846 if (xmlOutputCallbackInitialized == 0)
2847 xmlRegisterDefaultOutputCallbacks();
2848
2849 if (file == NULL) return(NULL);
2850
Daniel Veillardda3fee42008-09-01 13:08:57 +00002851 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002852 if (ret != NULL) {
2853 ret->context = file;
2854 ret->writecallback = xmlFileWrite;
2855 ret->closecallback = xmlFileFlush;
2856 }
2857
2858 return(ret);
2859}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002860
2861/**
2862 * xmlOutputBufferCreateBuffer:
2863 * @buffer: a xmlBufferPtr
2864 * @encoder: the encoding converter or NULL
2865 *
2866 * Create a buffered output for the progressive saving to a xmlBuffer
2867 *
2868 * Returns the new parser output or NULL
2869 */
2870xmlOutputBufferPtr
2871xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2872 xmlCharEncodingHandlerPtr encoder) {
2873 xmlOutputBufferPtr ret;
2874
2875 if (buffer == NULL) return(NULL);
2876
Nick Wellnhofer86615e42017-11-09 17:47:47 +01002877 ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer,
2878 encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002879
2880 return(ret);
2881}
2882
Daniel Veillarde258ade2012-08-06 11:16:30 +08002883/**
2884 * xmlOutputBufferGetContent:
2885 * @out: an xmlOutputBufferPtr
2886 *
2887 * Gives a pointer to the data currently held in the output buffer
2888 *
2889 * Returns a pointer to the data or NULL in case of error
2890 */
2891const xmlChar *
2892xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2893 if ((out == NULL) || (out->buffer == NULL))
2894 return(NULL);
2895
2896 return(xmlBufContent(out->buffer));
2897}
2898
2899/**
2900 * xmlOutputBufferGetSize:
2901 * @out: an xmlOutputBufferPtr
2902 *
2903 * Gives the length of the data currently held in the output buffer
2904 *
2905 * Returns 0 in case or error or no data is held, the size otherwise
2906 */
2907size_t
2908xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2909 if ((out == NULL) || (out->buffer == NULL))
2910 return(0);
2911
2912 return(xmlBufUse(out->buffer));
2913}
2914
2915
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002916#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002917
2918/**
2919 * xmlParserInputBufferCreateFd:
2920 * @fd: a file descriptor number
2921 * @enc: the charset encoding if known
2922 *
2923 * Create a buffered parser input for the progressive parsing for the input
2924 * from a file descriptor
2925 *
2926 * Returns the new parser input or NULL
2927 */
2928xmlParserInputBufferPtr
2929xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2930 xmlParserInputBufferPtr ret;
2931
2932 if (fd < 0) return(NULL);
2933
2934 ret = xmlAllocParserInputBuffer(enc);
2935 if (ret != NULL) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02002936 ret->context = (void *) (ptrdiff_t) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002937 ret->readcallback = xmlFdRead;
2938 ret->closecallback = xmlFdClose;
2939 }
2940
2941 return(ret);
2942}
2943
2944/**
2945 * xmlParserInputBufferCreateMem:
2946 * @mem: the memory input
2947 * @size: the length of the memory block
2948 * @enc: the charset encoding if known
2949 *
2950 * Create a buffered parser input for the progressive parsing for the input
2951 * from a memory area.
2952 *
2953 * Returns the new parser input or NULL
2954 */
2955xmlParserInputBufferPtr
2956xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2957 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002958 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002959
Nick Wellnhofer94f6ce82017-06-08 22:36:09 +02002960 if (size < 0) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002961 if (mem == NULL) return(NULL);
2962
2963 ret = xmlAllocParserInputBuffer(enc);
2964 if (ret != NULL) {
2965 ret->context = (void *) mem;
Vlad Tsyrklevich28f52fe2017-08-10 15:08:48 -07002966 ret->readcallback = xmlInputReadCallbackNop;
Owen Taylor3473f882001-02-23 17:55:21 +00002967 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002968 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00002969 if (errcode != 0) {
2970 xmlFree(ret);
2971 return(NULL);
2972 }
Owen Taylor3473f882001-02-23 17:55:21 +00002973 }
2974
2975 return(ret);
2976}
2977
2978/**
Daniel Veillard53350552003-09-18 13:35:51 +00002979 * xmlParserInputBufferCreateStatic:
2980 * @mem: the memory input
2981 * @size: the length of the memory block
2982 * @enc: the charset encoding if known
2983 *
2984 * Create a buffered parser input for the progressive parsing for the input
2985 * from an immutable memory area. This will not copy the memory area to
2986 * the buffer, but the memory is expected to be available until the end of
2987 * the parsing, this is useful for example when using mmap'ed file.
2988 *
2989 * Returns the new parser input or NULL
2990 */
2991xmlParserInputBufferPtr
2992xmlParserInputBufferCreateStatic(const char *mem, int size,
2993 xmlCharEncoding enc) {
2994 xmlParserInputBufferPtr ret;
2995
Nick Wellnhofer94f6ce82017-06-08 22:36:09 +02002996 if (size < 0) return(NULL);
Daniel Veillard53350552003-09-18 13:35:51 +00002997 if (mem == NULL) return(NULL);
2998
2999 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3000 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003001 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003002 return(NULL);
3003 }
3004 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003005 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003006 if (ret->buffer == NULL) {
3007 xmlFree(ret);
3008 return(NULL);
3009 }
3010 ret->encoder = xmlGetCharEncodingHandler(enc);
3011 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003012 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00003013 else
3014 ret->raw = NULL;
3015 ret->compressed = -1;
3016 ret->context = (void *) mem;
3017 ret->readcallback = NULL;
3018 ret->closecallback = NULL;
3019
3020 return(ret);
3021}
3022
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003023#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003024/**
Owen Taylor3473f882001-02-23 17:55:21 +00003025 * xmlOutputBufferCreateFd:
3026 * @fd: a file descriptor number
3027 * @encoder: the encoding converter or NULL
3028 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003029 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003030 * to a file descriptor
3031 *
3032 * Returns the new parser output or NULL
3033 */
3034xmlOutputBufferPtr
3035xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3036 xmlOutputBufferPtr ret;
3037
3038 if (fd < 0) return(NULL);
3039
Daniel Veillardda3fee42008-09-01 13:08:57 +00003040 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003041 if (ret != NULL) {
Nick Wellnhoferd422b952017-10-09 13:37:42 +02003042 ret->context = (void *) (ptrdiff_t) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003043 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003044 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003045 }
3046
3047 return(ret);
3048}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003049#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003050
3051/**
3052 * xmlParserInputBufferCreateIO:
3053 * @ioread: an I/O read function
3054 * @ioclose: an I/O close function
3055 * @ioctx: an I/O handler
3056 * @enc: the charset encoding if known
3057 *
3058 * Create a buffered parser input for the progressive parsing for the input
3059 * from an I/O handler
3060 *
3061 * Returns the new parser input or NULL
3062 */
3063xmlParserInputBufferPtr
3064xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3065 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3066 xmlParserInputBufferPtr ret;
3067
3068 if (ioread == NULL) return(NULL);
3069
3070 ret = xmlAllocParserInputBuffer(enc);
3071 if (ret != NULL) {
3072 ret->context = (void *) ioctx;
3073 ret->readcallback = ioread;
3074 ret->closecallback = ioclose;
3075 }
3076
3077 return(ret);
3078}
3079
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003080#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003081/**
3082 * xmlOutputBufferCreateIO:
3083 * @iowrite: an I/O write function
3084 * @ioclose: an I/O close function
3085 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003086 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003087 *
3088 * Create a buffered output for the progressive saving
3089 * to an I/O handler
3090 *
3091 * Returns the new parser output or NULL
3092 */
3093xmlOutputBufferPtr
3094xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3095 xmlOutputCloseCallback ioclose, void *ioctx,
3096 xmlCharEncodingHandlerPtr encoder) {
3097 xmlOutputBufferPtr ret;
3098
3099 if (iowrite == NULL) return(NULL);
3100
Daniel Veillardda3fee42008-09-01 13:08:57 +00003101 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003102 if (ret != NULL) {
3103 ret->context = (void *) ioctx;
3104 ret->writecallback = iowrite;
3105 ret->closecallback = ioclose;
3106 }
3107
3108 return(ret);
3109}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003110#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003111
3112/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003113 * xmlParserInputBufferCreateFilenameDefault:
3114 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3115 *
3116 * Registers a callback for URI input file handling
3117 *
3118 * Returns the old value of the registration function
3119 */
3120xmlParserInputBufferCreateFilenameFunc
3121xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3122{
3123 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3124 if (old == NULL) {
3125 old = __xmlParserInputBufferCreateFilename;
3126 }
3127
3128 xmlParserInputBufferCreateFilenameValue = func;
3129 return(old);
3130}
3131
3132/**
3133 * xmlOutputBufferCreateFilenameDefault:
3134 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3135 *
3136 * Registers a callback for URI output file handling
3137 *
3138 * Returns the old value of the registration function
3139 */
3140xmlOutputBufferCreateFilenameFunc
3141xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3142{
3143 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3144#ifdef LIBXML_OUTPUT_ENABLED
3145 if (old == NULL) {
3146 old = __xmlOutputBufferCreateFilename;
3147 }
3148#endif
3149 xmlOutputBufferCreateFilenameValue = func;
3150 return(old);
3151}
3152
3153/**
Owen Taylor3473f882001-02-23 17:55:21 +00003154 * xmlParserInputBufferPush:
3155 * @in: a buffered parser input
3156 * @len: the size in bytes of the array.
3157 * @buf: an char array
3158 *
3159 * Push the content of the arry in the input buffer
3160 * This routine handle the I18N transcoding to internal UTF-8
3161 * This is used when operating the parser in progressive (push) mode.
3162 *
3163 * Returns the number of chars read and stored in the buffer, or -1
3164 * in case of error.
3165 */
3166int
3167xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3168 int len, const char *buf) {
3169 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003170 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003171
3172 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003173 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003174 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003175 unsigned int use;
3176
Owen Taylor3473f882001-02-23 17:55:21 +00003177 /*
3178 * Store the data in the incoming raw buffer
3179 */
3180 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003181 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003182 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003183 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003184 if (ret != 0)
3185 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003186
3187 /*
3188 * convert as much as possible to the parser reading buffer.
3189 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003190 use = xmlBufUse(in->raw);
Elliott Hughes7fbecab2019-01-10 16:42:03 -08003191 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003192 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003193 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003194 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003195 return(-1);
3196 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003197 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003198 } else {
3199 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003200 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003201 if (ret != 0)
3202 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003203 }
3204#ifdef DEBUG_INPUT
3205 xmlGenericError(xmlGenericErrorContext,
3206 "I/O: pushed %d chars, buffer %d/%d\n",
Roumen Petrov89b6f732012-08-04 05:09:56 +03003207 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003208#endif
3209 return(nbchars);
3210}
3211
3212/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003213 * endOfInput:
3214 *
3215 * When reading from an Input channel indicated end of file or error
3216 * don't reread from it again.
3217 */
3218static int
3219endOfInput (void * context ATTRIBUTE_UNUSED,
3220 char * buffer ATTRIBUTE_UNUSED,
3221 int len ATTRIBUTE_UNUSED) {
3222 return(0);
3223}
3224
3225/**
Owen Taylor3473f882001-02-23 17:55:21 +00003226 * xmlParserInputBufferGrow:
3227 * @in: a buffered parser input
3228 * @len: indicative value of the amount of chars to read
3229 *
3230 * Grow up the content of the input buffer, the old data are preserved
3231 * This routine handle the I18N transcoding to internal UTF-8
3232 * This routine is used when operating the parser in normal (pull) mode
3233 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003234 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003235 * onto in->buffer or in->raw
3236 *
3237 * Returns the number of chars read and stored in the buffer, or -1
3238 * in case of error.
3239 */
3240int
3241xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3242 char *buffer = NULL;
3243 int res = 0;
3244 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003245
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003246 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003247 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003248 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003249
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003250 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003251 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003252 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003253 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003254 }
Owen Taylor3473f882001-02-23 17:55:21 +00003255
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003256 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3257 xmlIOErrMemory("growing input buffer");
3258 in->error = XML_ERR_NO_MEMORY;
3259 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003260 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003261 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003262
3263 /*
3264 * Call the read method for this I/O type.
3265 */
3266 if (in->readcallback != NULL) {
3267 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003268 if (res <= 0)
3269 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003270 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003271 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003272 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003273 return(-1);
3274 }
3275 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003276 return(-1);
3277 }
Daniel Veillard63588f42013-05-10 14:01:46 +08003278
3279 /*
3280 * try to establish compressed status of input if not done already
3281 */
3282 if (in->compressed == -1) {
Daniel Veillard18b89882015-11-03 15:46:29 +08003283#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08003284 if (in->readcallback == xmlXzfileRead)
3285 in->compressed = __libxml2_xzcompressed(in->context);
3286#endif
3287 }
3288
Owen Taylor3473f882001-02-23 17:55:21 +00003289 len = res;
3290 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003291 unsigned int use;
3292
Owen Taylor3473f882001-02-23 17:55:21 +00003293 /*
3294 * Store the data in the incoming raw buffer
3295 */
3296 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003297 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003298 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003299 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003300 if (res != 0)
3301 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003302
3303 /*
3304 * convert as much as possible to the parser reading buffer.
3305 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003306 use = xmlBufUse(in->raw);
Elliott Hughes7fbecab2019-01-10 16:42:03 -08003307 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003308 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003309 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003310 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003311 return(-1);
3312 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003313 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003314 } else {
3315 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003316 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003317 }
3318#ifdef DEBUG_INPUT
3319 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003320 "I/O: read %d chars, buffer %d\n",
3321 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003322#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003323 return(nbchars);
3324}
3325
3326/**
3327 * xmlParserInputBufferRead:
3328 * @in: a buffered parser input
3329 * @len: indicative value of the amount of chars to read
3330 *
3331 * Refresh the content of the input buffer, the old data are considered
3332 * consumed
3333 * This routine handle the I18N transcoding to internal UTF-8
3334 *
3335 * Returns the number of chars read and stored in the buffer, or -1
3336 * in case of error.
3337 */
3338int
3339xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003340 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003341 if (in->readcallback != NULL)
3342 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003343 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003344 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003345 else
3346 return(-1);
3347}
3348
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003349#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003350/**
3351 * xmlOutputBufferWrite:
3352 * @out: a buffered parser output
3353 * @len: the size in bytes of the array.
3354 * @buf: an char array
3355 *
3356 * Write the content of the array in the output I/O buffer
3357 * This routine handle the I18N transcoding from internal UTF-8
3358 * The buffer is lossless, i.e. will store in case of partial
3359 * or delayed writes.
3360 *
3361 * Returns the number of chars immediately written, or -1
3362 * in case of error.
3363 */
3364int
3365xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3366 int nbchars = 0; /* number of chars to output to I/O */
3367 int ret; /* return from function call */
3368 int written = 0; /* number of char written to I/O so far */
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003369 int chunk; /* number of byte current processed from buf */
Owen Taylor3473f882001-02-23 17:55:21 +00003370
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003371 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003372 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003373 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003374
3375 do {
3376 chunk = len;
3377 if (chunk > 4 * MINLEN)
3378 chunk = 4 * MINLEN;
3379
3380 /*
3381 * first handle encoding stuff.
3382 */
3383 if (out->encoder != NULL) {
3384 /*
3385 * Store the data in the incoming raw buffer
3386 */
3387 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003388 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003389 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003390 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003391 if (ret != 0)
3392 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003393
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003394 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003395 goto done;
3396
3397 /*
3398 * convert as much as possible to the parser reading buffer.
3399 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003400 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003401 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003402 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003403 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003404 return(-1);
3405 }
Elliott Hughes60f5c162021-08-20 17:09:52 -07003406 if (out->writecallback)
3407 nbchars = xmlBufUse(out->conv);
3408 else
3409 nbchars = ret >= 0 ? ret : 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003410 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003411 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003412 if (ret != 0)
3413 return(-1);
Elliott Hughes60f5c162021-08-20 17:09:52 -07003414 if (out->writecallback)
3415 nbchars = xmlBufUse(out->buffer);
3416 else
3417 nbchars = chunk;
Owen Taylor3473f882001-02-23 17:55:21 +00003418 }
3419 buf += chunk;
3420 len -= chunk;
3421
Owen Taylor3473f882001-02-23 17:55:21 +00003422 if (out->writecallback) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003423 if ((nbchars < MINLEN) && (len <= 0))
3424 goto done;
3425
Owen Taylor3473f882001-02-23 17:55:21 +00003426 /*
3427 * second write the stuff to the I/O channel
3428 */
3429 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003430 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003431 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003432 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003433 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003434 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003435 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003436 (const char *)xmlBufContent(out->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003437 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003438 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003439 }
3440 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003441 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003442 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003443 return(ret);
3444 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003445 if (out->written > INT_MAX - ret)
3446 out->written = INT_MAX;
3447 else
3448 out->written += ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003449 }
3450 written += nbchars;
3451 } while (len > 0);
3452
3453done:
3454#ifdef DEBUG_INPUT
3455 xmlGenericError(xmlGenericErrorContext,
3456 "I/O: wrote %d chars\n", written);
3457#endif
3458 return(written);
3459}
3460
3461/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003462 * xmlEscapeContent:
3463 * @out: a pointer to an array of bytes to store the result
3464 * @outlen: the length of @out
3465 * @in: a pointer to an array of unescaped UTF-8 bytes
3466 * @inlen: the length of @in
3467 *
3468 * Take a block of UTF-8 chars in and escape them.
3469 * Returns 0 if success, or -1 otherwise
3470 * The value of @inlen after return is the number of octets consumed
3471 * if the return value is positive, else unpredictable.
3472 * The value of @outlen after return is the number of octets consumed.
3473 */
3474static int
3475xmlEscapeContent(unsigned char* out, int *outlen,
3476 const xmlChar* in, int *inlen) {
3477 unsigned char* outstart = out;
3478 const unsigned char* base = in;
3479 unsigned char* outend = out + *outlen;
3480 const unsigned char* inend;
3481
3482 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003483
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003484 while ((in < inend) && (out < outend)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003485 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003486 if (outend - out < 4) break;
3487 *out++ = '&';
3488 *out++ = 'l';
3489 *out++ = 't';
3490 *out++ = ';';
3491 } else if (*in == '>') {
3492 if (outend - out < 4) break;
3493 *out++ = '&';
3494 *out++ = 'g';
3495 *out++ = 't';
3496 *out++ = ';';
3497 } else if (*in == '&') {
3498 if (outend - out < 5) break;
3499 *out++ = '&';
3500 *out++ = 'a';
3501 *out++ = 'm';
3502 *out++ = 'p';
3503 *out++ = ';';
3504 } else if (*in == '\r') {
3505 if (outend - out < 5) break;
3506 *out++ = '&';
3507 *out++ = '#';
3508 *out++ = '1';
3509 *out++ = '3';
3510 *out++ = ';';
3511 } else {
3512 *out++ = (unsigned char) *in;
3513 }
3514 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003515 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003516 *outlen = out - outstart;
3517 *inlen = in - base;
3518 return(0);
3519}
3520
3521/**
3522 * xmlOutputBufferWriteEscape:
3523 * @out: a buffered parser output
3524 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003525 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003526 *
3527 * Write the content of the string in the output I/O buffer
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003528 * This routine escapes the characters and then handle the I18N
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003529 * transcoding from internal UTF-8
3530 * The buffer is lossless, i.e. will store in case of partial
3531 * or delayed writes.
3532 *
3533 * Returns the number of chars immediately written, or -1
3534 * in case of error.
3535 */
3536int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003537xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3538 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003539 int nbchars = 0; /* number of chars to output to I/O */
3540 int ret; /* return from function call */
3541 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003542 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003543 int chunk; /* number of byte currently processed from str */
3544 int len; /* number of bytes in str */
3545 int cons; /* byte from str consumed */
3546
Daniel Veillardce244ad2004-11-05 10:03:46 +00003547 if ((out == NULL) || (out->error) || (str == NULL) ||
3548 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003549 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3550 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003551 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003552 if (len < 0) return(0);
3553 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003554 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003555
3556 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003557 oldwritten = written;
3558
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003559 /*
3560 * how many bytes to consume and how many bytes to store.
3561 */
3562 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003563 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003564
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003565 /*
3566 * make sure we have enough room to save first, if this is
3567 * not the case force a flush, but make sure we stay in the loop
3568 */
3569 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003570 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003571 return(-1);
3572 oldwritten = -1;
3573 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003574 }
3575
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003576 /*
3577 * first handle encoding stuff.
3578 */
3579 if (out->encoder != NULL) {
3580 /*
3581 * Store the data in the incoming raw buffer
3582 */
3583 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003584 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003585 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003586 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003587 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003588 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003589 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003590 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003591
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003592 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003593 goto done;
3594
3595 /*
3596 * convert as much as possible to the output buffer.
3597 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003598 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003599 if ((ret < 0) && (ret != -3)) {
3600 xmlIOErr(XML_IO_ENCODER, NULL);
3601 out->error = XML_IO_ENCODER;
3602 return(-1);
3603 }
Elliott Hughes60f5c162021-08-20 17:09:52 -07003604 if (out->writecallback)
3605 nbchars = xmlBufUse(out->conv);
3606 else
3607 nbchars = ret >= 0 ? ret : 0;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003608 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003609 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003610 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003611 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003612 xmlBufAddLen(out->buffer, chunk);
Elliott Hughes60f5c162021-08-20 17:09:52 -07003613 if (out->writecallback)
3614 nbchars = xmlBufUse(out->buffer);
3615 else
3616 nbchars = chunk;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003617 }
3618 str += cons;
3619 len -= cons;
3620
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003621 if (out->writecallback) {
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003622 if ((nbchars < MINLEN) && (len <= 0))
3623 goto done;
3624
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003625 /*
3626 * second write the stuff to the I/O channel
3627 */
3628 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003629 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003630 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003631 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003632 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003633 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003634 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003635 (const char *)xmlBufContent(out->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003636 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003637 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003638 }
3639 if (ret < 0) {
3640 xmlIOErr(XML_IO_WRITE, NULL);
3641 out->error = XML_IO_WRITE;
3642 return(ret);
3643 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003644 if (out->written > INT_MAX - ret)
3645 out->written = INT_MAX;
3646 else
3647 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003648 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3649 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003650 }
3651 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003652 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003653
3654done:
3655#ifdef DEBUG_INPUT
3656 xmlGenericError(xmlGenericErrorContext,
3657 "I/O: wrote %d chars\n", written);
3658#endif
3659 return(written);
3660}
3661
3662/**
Owen Taylor3473f882001-02-23 17:55:21 +00003663 * xmlOutputBufferWriteString:
3664 * @out: a buffered parser output
3665 * @str: a zero terminated C string
3666 *
3667 * Write the content of the string in the output I/O buffer
3668 * This routine handle the I18N transcoding from internal UTF-8
3669 * The buffer is lossless, i.e. will store in case of partial
3670 * or delayed writes.
3671 *
3672 * Returns the number of chars immediately written, or -1
3673 * in case of error.
3674 */
3675int
3676xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3677 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003678
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003679 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003680 if (str == NULL)
3681 return(-1);
3682 len = strlen(str);
3683
3684 if (len > 0)
3685 return(xmlOutputBufferWrite(out, len, str));
3686 return(len);
3687}
3688
3689/**
3690 * xmlOutputBufferFlush:
3691 * @out: a buffered output
3692 *
3693 * flushes the output I/O channel
3694 *
3695 * Returns the number of byte written or -1 in case of error.
3696 */
3697int
3698xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3699 int nbchars = 0, ret = 0;
3700
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003701 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003702 /*
3703 * first handle encoding stuff.
3704 */
3705 if ((out->conv != NULL) && (out->encoder != NULL)) {
3706 /*
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003707 * convert as much as possible to the parser output buffer.
Owen Taylor3473f882001-02-23 17:55:21 +00003708 */
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003709 do {
3710 nbchars = xmlCharEncOutput(out, 0);
3711 if (nbchars < 0) {
3712 xmlIOErr(XML_IO_ENCODER, NULL);
3713 out->error = XML_IO_ENCODER;
3714 return(-1);
3715 }
3716 } while (nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003717 }
3718
3719 /*
3720 * second flush the stuff to the I/O channel
3721 */
3722 if ((out->conv != NULL) && (out->encoder != NULL) &&
3723 (out->writecallback != NULL)) {
3724 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003725 (const char *)xmlBufContent(out->conv),
3726 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003727 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003728 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003729 } else if (out->writecallback != NULL) {
3730 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003731 (const char *)xmlBufContent(out->buffer),
3732 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003733 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003734 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003735 }
3736 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003737 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003738 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003739 return(ret);
3740 }
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003741 if (out->written > INT_MAX - ret)
3742 out->written = INT_MAX;
3743 else
3744 out->written += ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003745
3746#ifdef DEBUG_INPUT
3747 xmlGenericError(xmlGenericErrorContext,
3748 "I/O: flushed %d chars\n", ret);
3749#endif
3750 return(ret);
3751}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003752#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003753
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003754/**
Owen Taylor3473f882001-02-23 17:55:21 +00003755 * xmlParserGetDirectory:
3756 * @filename: the path to a file
3757 *
3758 * lookup the directory for that file
3759 *
3760 * Returns a new allocated string containing the directory, or NULL.
3761 */
3762char *
3763xmlParserGetDirectory(const char *filename) {
3764 char *ret = NULL;
3765 char dir[1024];
3766 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003767
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003768#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3769 return NULL;
3770#endif
3771
Owen Taylor3473f882001-02-23 17:55:21 +00003772 if (xmlInputCallbackInitialized == 0)
3773 xmlRegisterDefaultInputCallbacks();
3774
3775 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003776
Nick Wellnhofere3890542017-10-09 00:20:01 +02003777#if defined(_WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003778# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3779#else
3780# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003781#endif
3782
3783 strncpy(dir, filename, 1023);
3784 dir[1023] = 0;
3785 cur = &dir[strlen(dir)];
3786 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003787 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003788 cur --;
3789 }
Rob Richardsf779da32007-08-14 09:41:21 +00003790 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003791 if (cur == dir) dir[1] = 0;
3792 else *cur = 0;
3793 ret = xmlMemStrdup(dir);
3794 } else {
3795 if (getcwd(dir, 1024) != NULL) {
3796 dir[1023] = 0;
3797 ret = xmlMemStrdup(dir);
3798 }
3799 }
3800 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003801#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003802}
3803
3804/****************************************************************
3805 * *
3806 * External entities loading *
3807 * *
3808 ****************************************************************/
3809
Daniel Veillarda840b692003-10-19 13:35:37 +00003810/**
3811 * xmlCheckHTTPInput:
3812 * @ctxt: an XML parser context
3813 * @ret: an XML parser input
3814 *
3815 * Check an input in case it was created from an HTTP stream, in that
3816 * case it will handle encoding and update of the base URL in case of
3817 * redirection. It also checks for HTTP errors in which case the input
3818 * is cleanly freed up and an appropriate error is raised in context
3819 *
3820 * Returns the input or NULL in case of HTTP error.
3821 */
3822xmlParserInputPtr
3823xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
Elliott Hughesecdab2a2022-02-23 14:33:50 -08003824 /* Avoid unused variable warning if features are disabled. */
3825 (void) ctxt;
3826
Daniel Veillarda840b692003-10-19 13:35:37 +00003827#ifdef LIBXML_HTTP_ENABLED
3828 if ((ret != NULL) && (ret->buf != NULL) &&
3829 (ret->buf->readcallback == xmlIOHTTPRead) &&
3830 (ret->buf->context != NULL)) {
3831 const char *encoding;
3832 const char *redir;
3833 const char *mime;
3834 int code;
3835
3836 code = xmlNanoHTTPReturnCode(ret->buf->context);
3837 if (code >= 400) {
3838 /* fatal error */
3839 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003840 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003841 (const char *) ret->filename);
3842 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003843 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003844 xmlFreeInputStream(ret);
3845 ret = NULL;
3846 } else {
3847
3848 mime = xmlNanoHTTPMimeType(ret->buf->context);
3849 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3850 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3851 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3852 if (encoding != NULL) {
3853 xmlCharEncodingHandlerPtr handler;
3854
3855 handler = xmlFindCharEncodingHandler(encoding);
3856 if (handler != NULL) {
3857 xmlSwitchInputEncoding(ctxt, ret, handler);
3858 } else {
3859 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3860 "Unknown encoding %s",
3861 BAD_CAST encoding, NULL);
3862 }
3863 if (ret->encoding == NULL)
3864 ret->encoding = xmlStrdup(BAD_CAST encoding);
3865 }
3866#if 0
3867 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3868#endif
3869 }
3870 redir = xmlNanoHTTPRedir(ret->buf->context);
3871 if (redir != NULL) {
3872 if (ret->filename != NULL)
3873 xmlFree((xmlChar *) ret->filename);
3874 if (ret->directory != NULL) {
3875 xmlFree((xmlChar *) ret->directory);
3876 ret->directory = NULL;
3877 }
3878 ret->filename =
3879 (char *) xmlStrdup((const xmlChar *) redir);
3880 }
3881 }
3882 }
3883#endif
3884 return(ret);
3885}
3886
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003887static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003888 const char *path;
3889
3890 if (URL == NULL)
3891 return(0);
3892
Daniel Veillardf4862f02002-09-10 11:13:43 +00003893 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003894#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003895 path = &URL[17];
3896#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003897 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003898#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003899 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003900#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003901 path = &URL[8];
3902#else
3903 path = &URL[7];
3904#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003905 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003906 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003907
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003908 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003909}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003910
Daniel Veillardad4e2962006-09-21 08:36:38 +00003911#ifdef LIBXML_CATALOG_ENABLED
3912
3913/**
3914 * xmlResolveResourceFromCatalog:
3915 * @URL: the URL for the entity to load
3916 * @ID: the System ID for the entity to load
3917 * @ctxt: the context in which the entity is called or NULL
3918 *
3919 * Resolves the URL and ID against the appropriate catalog.
3920 * This function is used by xmlDefaultExternalEntityLoader and
3921 * xmlNoNetExternalEntityLoader.
3922 *
3923 * Returns a new allocated URL, or NULL.
3924 */
William M. Brack38d452a2007-05-22 16:00:06 +00003925static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003926xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3927 xmlParserCtxtPtr ctxt) {
3928 xmlChar *resource = NULL;
3929 xmlCatalogAllow pref;
3930
3931 /*
3932 * If the resource doesn't exists as a file,
3933 * try to load it from the resource pointed in the catalogs
3934 */
3935 pref = xmlCatalogGetDefaults();
3936
3937 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3938 /*
3939 * Do a local lookup
3940 */
3941 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3942 ((pref == XML_CATA_ALLOW_ALL) ||
3943 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3944 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3945 (const xmlChar *)ID,
3946 (const xmlChar *)URL);
3947 }
3948 /*
3949 * Try a global lookup
3950 */
3951 if ((resource == NULL) &&
3952 ((pref == XML_CATA_ALLOW_ALL) ||
3953 (pref == XML_CATA_ALLOW_GLOBAL))) {
3954 resource = xmlCatalogResolve((const xmlChar *)ID,
3955 (const xmlChar *)URL);
3956 }
3957 if ((resource == NULL) && (URL != NULL))
3958 resource = xmlStrdup((const xmlChar *) URL);
3959
3960 /*
3961 * TODO: do an URI lookup on the reference
3962 */
3963 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3964 xmlChar *tmp = NULL;
3965
3966 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3967 ((pref == XML_CATA_ALLOW_ALL) ||
3968 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3969 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3970 }
3971 if ((tmp == NULL) &&
3972 ((pref == XML_CATA_ALLOW_ALL) ||
3973 (pref == XML_CATA_ALLOW_GLOBAL))) {
3974 tmp = xmlCatalogResolveURI(resource);
3975 }
3976
3977 if (tmp != NULL) {
3978 xmlFree(resource);
3979 resource = tmp;
3980 }
3981 }
3982 }
3983
3984 return resource;
3985}
3986
3987#endif
3988
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003989/**
Owen Taylor3473f882001-02-23 17:55:21 +00003990 * xmlDefaultExternalEntityLoader:
3991 * @URL: the URL for the entity to load
3992 * @ID: the System ID for the entity to load
3993 * @ctxt: the context in which the entity is called or NULL
3994 *
Haibo Huangcfd91dc2020-07-30 23:01:33 -07003995 * By default we don't load external entities, yet.
Owen Taylor3473f882001-02-23 17:55:21 +00003996 *
3997 * Returns a new allocated xmlParserInputPtr, or NULL.
3998 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003999static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00004000xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00004001 xmlParserCtxtPtr ctxt)
4002{
Owen Taylor3473f882001-02-23 17:55:21 +00004003 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00004004 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00004005
Owen Taylor3473f882001-02-23 17:55:21 +00004006#ifdef DEBUG_EXTERNAL_ENTITIES
4007 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00004008 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004009#endif
Nick Wellnhofer030b1f72017-06-06 15:53:42 +02004010 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
Daniel Veillard61b93382003-11-03 14:28:31 +00004011 int options = ctxt->options;
4012
Nick Wellnhofer030b1f72017-06-06 15:53:42 +02004013 ctxt->options -= XML_PARSE_NONET;
4014 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4015 ctxt->options = options;
4016 return(ret);
Daniel Veillard61b93382003-11-03 14:28:31 +00004017 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00004018#ifdef LIBXML_CATALOG_ENABLED
4019 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004020#endif
4021
4022 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004023 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004024
4025 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004026 if (ID == NULL)
4027 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004028 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004029 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004030 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004031 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004032 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004033 xmlFree(resource);
4034 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004035}
4036
4037static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4038 xmlDefaultExternalEntityLoader;
4039
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004040/**
Owen Taylor3473f882001-02-23 17:55:21 +00004041 * xmlSetExternalEntityLoader:
4042 * @f: the new entity resolver function
4043 *
4044 * Changes the defaultexternal entity resolver function for the application
4045 */
4046void
4047xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4048 xmlCurrentExternalEntityLoader = f;
4049}
4050
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004051/**
Owen Taylor3473f882001-02-23 17:55:21 +00004052 * xmlGetExternalEntityLoader:
4053 *
4054 * Get the default external entity resolver function for the application
4055 *
4056 * Returns the xmlExternalEntityLoader function pointer
4057 */
4058xmlExternalEntityLoader
4059xmlGetExternalEntityLoader(void) {
4060 return(xmlCurrentExternalEntityLoader);
4061}
4062
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004063/**
Owen Taylor3473f882001-02-23 17:55:21 +00004064 * xmlLoadExternalEntity:
4065 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004066 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004067 * @ctxt: the context in which the entity is called or NULL
4068 *
4069 * Load an external entity, note that the use of this function for
4070 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004071 *
4072 * Returns the xmlParserInputPtr or NULL
4073 */
4074xmlParserInputPtr
4075xmlLoadExternalEntity(const char *URL, const char *ID,
4076 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004077 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004078 char *canonicFilename;
4079 xmlParserInputPtr ret;
4080
4081 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4082 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004083 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004084 return(NULL);
4085 }
4086
4087 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4088 xmlFree(canonicFilename);
4089 return(ret);
4090 }
Owen Taylor3473f882001-02-23 17:55:21 +00004091 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4092}
4093
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004094/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004095 * *
4096 * Disabling Network access *
4097 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004098 ************************************************************************/
4099
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004100/**
4101 * xmlNoNetExternalEntityLoader:
4102 * @URL: the URL for the entity to load
4103 * @ID: the System ID for the entity to load
4104 * @ctxt: the context in which the entity is called or NULL
4105 *
4106 * A specific entity loader disabling network accesses, though still
4107 * allowing local catalog accesses for resolution.
4108 *
4109 * Returns a new allocated xmlParserInputPtr, or NULL.
4110 */
4111xmlParserInputPtr
4112xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4113 xmlParserCtxtPtr ctxt) {
4114 xmlParserInputPtr input = NULL;
4115 xmlChar *resource = NULL;
4116
4117#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004118 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004119#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004120
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004121 if (resource == NULL)
4122 resource = (xmlChar *) URL;
4123
4124 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004125 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4126 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004127 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004128 if (resource != (xmlChar *) URL)
4129 xmlFree(resource);
4130 return(NULL);
4131 }
4132 }
4133 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4134 if (resource != (xmlChar *) URL)
4135 xmlFree(resource);
4136 return(input);
4137}
4138