blob: 5baeba33888b5c7b7c4181f9e5bde5d8801e6488 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard344cee72001-08-20 00:08:40 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
10
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000013
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
Daniel Veillard92727042002-09-17 17:59:20 +000015#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000017#endif
18
Owen Taylor3473f882001-02-23 17:55:21 +000019
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
Anders F Bjorklundeae52612011-09-18 16:59:13 +020038#ifdef HAVE_LZMA_H
39#include <lzma.h>
40#endif
Owen Taylor3473f882001-02-23 17:55:21 +000041
Daniel Veillard59d3ed82007-04-17 12:44:58 +000042#if defined(WIN32) || defined(_WIN32)
Daniel Veillardf7416012006-04-27 08:15:20 +000043#include <windows.h>
44#endif
45
Daniel Veillard59d3ed82007-04-17 12:44:58 +000046#if defined(_WIN32_WCE)
47#include <winnls.h> /* for CP_UTF8 */
48#endif
49
Owen Taylor3473f882001-02-23 17:55:21 +000050/* Figure a portable way to know if a file is a directory. */
51#ifndef HAVE_STAT
52# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000053 /* MS C library seems to define stat and _stat. The definition
54 is identical. Still, mapping them to each other causes a warning. */
55# ifndef _MSC_VER
56# define stat(x,y) _stat(x,y)
57# endif
Owen Taylor3473f882001-02-23 17:55:21 +000058# define HAVE_STAT
59# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000060#else
61# ifdef HAVE__STAT
Daniel Veillard0da41662006-10-10 09:05:36 +000062# if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillard8ca85b22006-09-01 09:56:07 +000063# define stat _stat
Daniel Veillard0da41662006-10-10 09:05:36 +000064# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000065# endif
Owen Taylor3473f882001-02-23 17:55:21 +000066#endif
67#ifdef HAVE_STAT
68# ifndef S_ISDIR
69# ifdef _S_ISDIR
70# define S_ISDIR(x) _S_ISDIR(x)
71# else
72# ifdef S_IFDIR
73# ifndef S_IFMT
74# ifdef _S_IFMT
75# define S_IFMT _S_IFMT
76# endif
77# endif
78# ifdef S_IFMT
79# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
80# endif
81# endif
82# endif
83# endif
84#endif
85
86#include <libxml/xmlmemory.h>
87#include <libxml/parser.h>
88#include <libxml/parserInternals.h>
89#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000090#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000091#include <libxml/nanohttp.h>
92#include <libxml/nanoftp.h>
93#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000094#ifdef LIBXML_CATALOG_ENABLED
95#include <libxml/catalog.h>
96#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000097#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000098
Daniel Veillarda6a6e702012-07-16 14:22:54 +080099#include "buf.h"
100#include "enc.h"
101
Daniel Veillardf012a642001-07-23 19:10:52 +0000102/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000103/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +0000104/* #define DEBUG_INPUT */
105
106#ifdef DEBUG_INPUT
107#define MINLEN 40
108#else
109#define MINLEN 4000
110#endif
111
112/*
113 * Input I/O callback sets
114 */
115typedef struct _xmlInputCallback {
116 xmlInputMatchCallback matchcallback;
117 xmlInputOpenCallback opencallback;
118 xmlInputReadCallback readcallback;
119 xmlInputCloseCallback closecallback;
120} xmlInputCallback;
121
122#define MAX_INPUT_CALLBACK 15
123
Daniel Veillard22090732001-07-16 00:06:07 +0000124static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
125static int xmlInputCallbackNr = 0;
126static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000127
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000128#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000129/*
130 * Output I/O callback sets
131 */
132typedef struct _xmlOutputCallback {
133 xmlOutputMatchCallback matchcallback;
134 xmlOutputOpenCallback opencallback;
135 xmlOutputWriteCallback writecallback;
136 xmlOutputCloseCallback closecallback;
137} xmlOutputCallback;
138
139#define MAX_OUTPUT_CALLBACK 15
140
Daniel Veillard22090732001-07-16 00:06:07 +0000141static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
142static int xmlOutputCallbackNr = 0;
143static int xmlOutputCallbackInitialized = 0;
Daniel Veillardda3fee42008-09-01 13:08:57 +0000144
145xmlOutputBufferPtr
146xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000147#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000148
Daniel Veillard05d987b2003-10-08 11:54:57 +0000149/************************************************************************
150 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200151 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000152 * *
153 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000154
Daniel Veillard05d987b2003-10-08 11:54:57 +0000155static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000156 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000157 "Permission denied", /* EACCES */
158 "Resource temporarily unavailable",/* EAGAIN */
159 "Bad file descriptor", /* EBADF */
160 "Bad message", /* EBADMSG */
161 "Resource busy", /* EBUSY */
162 "Operation canceled", /* ECANCELED */
163 "No child processes", /* ECHILD */
164 "Resource deadlock avoided",/* EDEADLK */
165 "Domain error", /* EDOM */
166 "File exists", /* EEXIST */
167 "Bad address", /* EFAULT */
168 "File too large", /* EFBIG */
169 "Operation in progress", /* EINPROGRESS */
170 "Interrupted function call",/* EINTR */
171 "Invalid argument", /* EINVAL */
172 "Input/output error", /* EIO */
173 "Is a directory", /* EISDIR */
174 "Too many open files", /* EMFILE */
175 "Too many links", /* EMLINK */
176 "Inappropriate message buffer length",/* EMSGSIZE */
177 "Filename too long", /* ENAMETOOLONG */
178 "Too many open files in system",/* ENFILE */
179 "No such device", /* ENODEV */
180 "No such file or directory",/* ENOENT */
181 "Exec format error", /* ENOEXEC */
182 "No locks available", /* ENOLCK */
183 "Not enough space", /* ENOMEM */
184 "No space left on device", /* ENOSPC */
185 "Function not implemented", /* ENOSYS */
186 "Not a directory", /* ENOTDIR */
187 "Directory not empty", /* ENOTEMPTY */
188 "Not supported", /* ENOTSUP */
189 "Inappropriate I/O control operation",/* ENOTTY */
190 "No such device or address",/* ENXIO */
191 "Operation not permitted", /* EPERM */
192 "Broken pipe", /* EPIPE */
193 "Result too large", /* ERANGE */
194 "Read-only file system", /* EROFS */
195 "Invalid seek", /* ESPIPE */
196 "No such process", /* ESRCH */
197 "Operation timed out", /* ETIMEDOUT */
198 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000199 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000200 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000201 "flush error",
202 "write error",
203 "no input",
204 "buffer full",
205 "loading error",
206 "not a socket", /* ENOTSOCK */
207 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000208 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000209 "unreachable network", /* ENETUNREACH */
210 "adddress in use", /* EADDRINUSE */
211 "already in use", /* EALREADY */
212 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000213};
214
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000215#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000216/**
217 * __xmlIOWin32UTF8ToWChar:
218 * @u8String: uft-8 string
219 *
220 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
221 */
222static wchar_t *
223__xmlIOWin32UTF8ToWChar(const char *u8String)
224{
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000225 wchar_t *wString = NULL;
Daniel Veillardf7416012006-04-27 08:15:20 +0000226
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000227 if (u8String) {
228 int wLen =
229 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
230 -1, NULL, 0);
231 if (wLen) {
232 wString = xmlMalloc(wLen * sizeof(wchar_t));
233 if (wString) {
234 if (MultiByteToWideChar
235 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
236 xmlFree(wString);
237 wString = NULL;
238 }
239 }
240 }
241 }
242
243 return wString;
Daniel Veillardf7416012006-04-27 08:15:20 +0000244}
245#endif
246
Daniel Veillard05d987b2003-10-08 11:54:57 +0000247/**
248 * xmlIOErrMemory:
249 * @extra: extra informations
250 *
251 * Handle an out of memory condition
252 */
253static void
254xmlIOErrMemory(const char *extra)
255{
256 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
257}
258
259/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000260 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000261 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000262 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000263 * @extra: extra informations
264 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000265 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000266 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000267void
268__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000269{
270 unsigned int idx;
271
272 if (code == 0) {
273#ifdef HAVE_ERRNO_H
274 if (errno == 0) code = 0;
275#ifdef EACCES
276 else if (errno == EACCES) code = XML_IO_EACCES;
277#endif
278#ifdef EAGAIN
279 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
280#endif
281#ifdef EBADF
282 else if (errno == EBADF) code = XML_IO_EBADF;
283#endif
284#ifdef EBADMSG
285 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
286#endif
287#ifdef EBUSY
288 else if (errno == EBUSY) code = XML_IO_EBUSY;
289#endif
290#ifdef ECANCELED
291 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
292#endif
293#ifdef ECHILD
294 else if (errno == ECHILD) code = XML_IO_ECHILD;
295#endif
296#ifdef EDEADLK
297 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
298#endif
299#ifdef EDOM
300 else if (errno == EDOM) code = XML_IO_EDOM;
301#endif
302#ifdef EEXIST
303 else if (errno == EEXIST) code = XML_IO_EEXIST;
304#endif
305#ifdef EFAULT
306 else if (errno == EFAULT) code = XML_IO_EFAULT;
307#endif
308#ifdef EFBIG
309 else if (errno == EFBIG) code = XML_IO_EFBIG;
310#endif
311#ifdef EINPROGRESS
312 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
313#endif
314#ifdef EINTR
315 else if (errno == EINTR) code = XML_IO_EINTR;
316#endif
317#ifdef EINVAL
318 else if (errno == EINVAL) code = XML_IO_EINVAL;
319#endif
320#ifdef EIO
321 else if (errno == EIO) code = XML_IO_EIO;
322#endif
323#ifdef EISDIR
324 else if (errno == EISDIR) code = XML_IO_EISDIR;
325#endif
326#ifdef EMFILE
327 else if (errno == EMFILE) code = XML_IO_EMFILE;
328#endif
329#ifdef EMLINK
330 else if (errno == EMLINK) code = XML_IO_EMLINK;
331#endif
332#ifdef EMSGSIZE
333 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
334#endif
335#ifdef ENAMETOOLONG
336 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
337#endif
338#ifdef ENFILE
339 else if (errno == ENFILE) code = XML_IO_ENFILE;
340#endif
341#ifdef ENODEV
342 else if (errno == ENODEV) code = XML_IO_ENODEV;
343#endif
344#ifdef ENOENT
345 else if (errno == ENOENT) code = XML_IO_ENOENT;
346#endif
347#ifdef ENOEXEC
348 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
349#endif
350#ifdef ENOLCK
351 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
352#endif
353#ifdef ENOMEM
354 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
355#endif
356#ifdef ENOSPC
357 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
358#endif
359#ifdef ENOSYS
360 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
361#endif
362#ifdef ENOTDIR
363 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
364#endif
365#ifdef ENOTEMPTY
366 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
367#endif
368#ifdef ENOTSUP
369 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
370#endif
371#ifdef ENOTTY
372 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
373#endif
374#ifdef ENXIO
375 else if (errno == ENXIO) code = XML_IO_ENXIO;
376#endif
377#ifdef EPERM
378 else if (errno == EPERM) code = XML_IO_EPERM;
379#endif
380#ifdef EPIPE
381 else if (errno == EPIPE) code = XML_IO_EPIPE;
382#endif
383#ifdef ERANGE
384 else if (errno == ERANGE) code = XML_IO_ERANGE;
385#endif
386#ifdef EROFS
387 else if (errno == EROFS) code = XML_IO_EROFS;
388#endif
389#ifdef ESPIPE
390 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
391#endif
392#ifdef ESRCH
393 else if (errno == ESRCH) code = XML_IO_ESRCH;
394#endif
395#ifdef ETIMEDOUT
396 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
397#endif
398#ifdef EXDEV
399 else if (errno == EXDEV) code = XML_IO_EXDEV;
400#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000401#ifdef ENOTSOCK
402 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
403#endif
404#ifdef EISCONN
405 else if (errno == EISCONN) code = XML_IO_EISCONN;
406#endif
407#ifdef ECONNREFUSED
408 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
409#endif
410#ifdef ETIMEDOUT
411 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
412#endif
413#ifdef ENETUNREACH
414 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
415#endif
416#ifdef EADDRINUSE
417 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
418#endif
419#ifdef EINPROGRESS
420 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
421#endif
422#ifdef EALREADY
423 else if (errno == EALREADY) code = XML_IO_EALREADY;
424#endif
425#ifdef EAFNOSUPPORT
426 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
427#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000428 else code = XML_IO_UNKNOWN;
429#endif /* HAVE_ERRNO_H */
430 }
431 idx = 0;
432 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
433 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200434
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000435 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
436}
437
438/**
439 * xmlIOErr:
440 * @code: the error number
441 * @extra: extra informations
442 *
443 * Handle an I/O error
444 */
445static void
446xmlIOErr(int code, const char *extra)
447{
448 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000449}
450
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000451/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000452 * __xmlLoaderErr:
453 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000454 * @extra: extra informations
455 *
456 * Handle a resource access error
457 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000458void
459__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000460{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000461 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000462 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000463 xmlGenericErrorFunc channel = NULL;
464 void *data = NULL;
465 xmlErrorLevel level = XML_ERR_ERROR;
466
Daniel Veillard157fee02003-10-31 10:36:03 +0000467 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
468 (ctxt->instate == XML_PARSER_EOF))
469 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000470 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
471 if (ctxt->validate) {
472 channel = ctxt->sax->error;
473 level = XML_ERR_ERROR;
474 } else {
475 channel = ctxt->sax->warning;
476 level = XML_ERR_WARNING;
477 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000478 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
479 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000480 data = ctxt->userData;
481 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000482 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000483 XML_IO_LOAD_ERROR, level, NULL, 0,
484 filename, NULL, NULL, 0, 0,
485 msg, filename);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200486
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000487}
488
Daniel Veillard05d987b2003-10-08 11:54:57 +0000489/************************************************************************
490 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200491 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000492 * *
493 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000494/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000495 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000496 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000497 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000498 * This function is obsolete. Please see xmlURIFromPath in uri.c for
499 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000500 *
501 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000502 */
503xmlChar *
504xmlNormalizeWindowsPath(const xmlChar *path)
505{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000506 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000507}
508
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000509/**
510 * xmlCleanupInputCallbacks:
511 *
512 * clears the entire input callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200513 * compiled-in I/O.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000514 */
515void
516xmlCleanupInputCallbacks(void)
517{
518 int i;
519
520 if (!xmlInputCallbackInitialized)
521 return;
522
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000523 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000524 xmlInputCallbackTable[i].matchcallback = NULL;
525 xmlInputCallbackTable[i].opencallback = NULL;
526 xmlInputCallbackTable[i].readcallback = NULL;
527 xmlInputCallbackTable[i].closecallback = NULL;
528 }
529
530 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000531 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000532}
533
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000534/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000535 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000536 *
537 * Clear the top input callback from the input stack. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200538 * compiled-in I/O.
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000539 *
540 * Returns the number of input callback registered or -1 in case of error.
541 */
542int
543xmlPopInputCallbacks(void)
544{
545 if (!xmlInputCallbackInitialized)
546 return(-1);
547
548 if (xmlInputCallbackNr <= 0)
549 return(-1);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200550
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000551 xmlInputCallbackNr--;
552 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
553 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
554 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
555 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
556
557 return(xmlInputCallbackNr);
558}
559
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000560#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000561/**
562 * xmlCleanupOutputCallbacks:
563 *
564 * clears the entire output callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200565 * compiled-in I/O callbacks.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000566 */
567void
568xmlCleanupOutputCallbacks(void)
569{
570 int i;
571
572 if (!xmlOutputCallbackInitialized)
573 return;
574
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000575 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000576 xmlOutputCallbackTable[i].matchcallback = NULL;
577 xmlOutputCallbackTable[i].opencallback = NULL;
578 xmlOutputCallbackTable[i].writecallback = NULL;
579 xmlOutputCallbackTable[i].closecallback = NULL;
580 }
581
582 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000583 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000584}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000585#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000586
Owen Taylor3473f882001-02-23 17:55:21 +0000587/************************************************************************
588 * *
589 * Standard I/O for file accesses *
590 * *
591 ************************************************************************/
592
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000593#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
594
595/**
596 * xmlWrapOpenUtf8:
597 * @path: the path in utf-8 encoding
598 * @mode: type of access (0 - read, 1 - write)
599 *
600 * function opens the file specified by @path
601 *
602 */
603static FILE*
604xmlWrapOpenUtf8(const char *path,int mode)
605{
606 FILE *fd = NULL;
607 wchar_t *wPath;
608
609 wPath = __xmlIOWin32UTF8ToWChar(path);
610 if(wPath)
611 {
612 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
613 xmlFree(wPath);
614 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000615 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000616 if(fd == NULL)
617 fd = fopen(path, mode ? "wb" : "rb");
618
619 return fd;
620}
621
Rob Richards6c61e022009-08-12 11:41:27 -0400622#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200623static gzFile
624xmlWrapGzOpenUtf8(const char *path, const char *mode)
625{
626 gzFile fd;
627 wchar_t *wPath;
628
629 fd = gzopen (path, mode);
630 if (fd)
631 return fd;
632
633 wPath = __xmlIOWin32UTF8ToWChar(path);
634 if(wPath)
635 {
636 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
637#ifdef _O_BINARY
638 m |= (strstr(mode, "b") ? _O_BINARY : 0);
639#endif
640 d = _wopen(wPath, m);
641 if (d >= 0)
642 fd = gzdopen(d, mode);
643 xmlFree(wPath);
644 }
645
646 return fd;
647}
Rob Richards6c61e022009-08-12 11:41:27 -0400648#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200649
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000650/**
651 * xmlWrapStatUtf8:
652 * @path: the path in utf-8 encoding
653 * @info: structure that stores results
654 *
655 * function obtains information about the file or directory
656 *
657 */
658static int
659xmlWrapStatUtf8(const char *path,struct stat *info)
660{
661#ifdef HAVE_STAT
662 int retval = -1;
663 wchar_t *wPath;
664
665 wPath = __xmlIOWin32UTF8ToWChar(path);
666 if (wPath)
667 {
668 retval = _wstat(wPath,info);
669 xmlFree(wPath);
670 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000671 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000672 if(retval < 0)
673 retval = stat(path,info);
674 return retval;
675#else
676 return -1;
677#endif
678}
679
680/**
681 * xmlWrapOpenNative:
682 * @path: the path
683 * @mode: type of access (0 - read, 1 - write)
684 *
685 * function opens the file specified by @path
686 *
687 */
688static FILE*
689xmlWrapOpenNative(const char *path,int mode)
690{
691 return fopen(path,mode ? "wb" : "rb");
692}
693
694/**
695 * xmlWrapStatNative:
696 * @path: the path
697 * @info: structure that stores results
698 *
699 * function obtains information about the file or directory
700 *
701 */
702static int
703xmlWrapStatNative(const char *path,struct stat *info)
704{
705#ifdef HAVE_STAT
706 return stat(path,info);
707#else
708 return -1;
709#endif
710}
711
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000712typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
713static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
714typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
Rob Richards6460f922006-10-12 21:08:29 +0000715static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400716#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200717typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
718static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400719#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000720/**
721 * xmlInitPlatformSpecificIo:
722 *
723 * Initialize platform specific features.
724 */
725static void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000726xmlInitPlatformSpecificIo(void)
727{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000728 static int xmlPlatformIoInitialized = 0;
729 OSVERSIONINFO osvi;
730
731 if(xmlPlatformIoInitialized)
732 return;
733
734 osvi.dwOSVersionInfoSize = sizeof(osvi);
735
736 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
737 xmlWrapStat = xmlWrapStatUtf8;
738 xmlWrapOpen = xmlWrapOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400739#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200740 xmlWrapGzOpen = xmlWrapGzOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400741#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000742 } else {
743 xmlWrapStat = xmlWrapStatNative;
744 xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400745#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200746 xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400747#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000748 }
749
750 xmlPlatformIoInitialized = 1;
751 return;
752}
753
754#endif
755
Owen Taylor3473f882001-02-23 17:55:21 +0000756/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000757 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000758 * @path: the path to check
759 *
760 * function checks to see if @path is a valid source
761 * (file, socket...) for XML.
762 *
763 * if stat is not available on the target machine,
764 * returns 1. if stat fails, returns 0 (if calling
765 * stat on the filename fails, it can't be right).
766 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000767 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000768 */
769
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000770int
Owen Taylor3473f882001-02-23 17:55:21 +0000771xmlCheckFilename (const char *path)
772{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000773#ifdef HAVE_STAT
Michael Stahl55b899a2012-09-07 12:14:00 +0800774 struct stat stat_buffer;
Daniel Veillard0b309952006-05-02 20:34:38 +0000775#endif
Michael Stahl55b899a2012-09-07 12:14:00 +0800776 if (path == NULL)
777 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000778
Owen Taylor3473f882001-02-23 17:55:21 +0000779#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000780#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Michael Stahl55b899a2012-09-07 12:14:00 +0800781 /*
782 * On Windows stat and wstat do not work with long pathname,
783 * which start with '\\?\'
784 */
785 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
786 (path[3] == '\\') )
787 return 1;
788
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000789 if (xmlWrapStat(path, &stat_buffer) == -1)
790 return 0;
791#else
Owen Taylor3473f882001-02-23 17:55:21 +0000792 if (stat(path, &stat_buffer) == -1)
793 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000794#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000795#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000796 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000797 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000798#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000799#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000800 return 1;
801}
802
Daniel Veillard153cf152012-10-26 13:50:47 +0800803int
Owen Taylor3473f882001-02-23 17:55:21 +0000804xmlNop(void) {
805 return(0);
806}
807
808/**
Owen Taylor3473f882001-02-23 17:55:21 +0000809 * xmlFdRead:
810 * @context: the I/O context
811 * @buffer: where to drop data
812 * @len: number of bytes to read
813 *
814 * Read @len bytes to @buffer from the I/O channel.
815 *
816 * Returns the number of bytes written
817 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000818static int
Owen Taylor3473f882001-02-23 17:55:21 +0000819xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000820 int ret;
821
822 ret = read((int) (long) context, &buffer[0], len);
823 if (ret < 0) xmlIOErr(0, "read()");
824 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000825}
826
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000827#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000828/**
829 * xmlFdWrite:
830 * @context: the I/O context
831 * @buffer: where to get data
832 * @len: number of bytes to write
833 *
834 * Write @len bytes from @buffer to the I/O channel.
835 *
836 * Returns the number of bytes written
837 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000838static int
Owen Taylor3473f882001-02-23 17:55:21 +0000839xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000840 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000841
Daniel Veillard9b693b42005-10-28 14:54:17 +0000842 if (len > 0) {
843 ret = write((int) (long) context, &buffer[0], len);
844 if (ret < 0) xmlIOErr(0, "write()");
845 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000846 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000847}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000848#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000849
850/**
851 * xmlFdClose:
852 * @context: the I/O context
853 *
854 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000855 *
856 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000857 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000858static int
Owen Taylor3473f882001-02-23 17:55:21 +0000859xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000860 int ret;
861 ret = close((int) (long) context);
862 if (ret < 0) xmlIOErr(0, "close()");
863 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000864}
865
866/**
867 * xmlFileMatch:
868 * @filename: the URI for matching
869 *
870 * input from FILE *
871 *
872 * Returns 1 if matches, 0 otherwise
873 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000874int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000875xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000876 return(1);
877}
878
879/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000880 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000881 * @filename: the URI for matching
882 *
883 * input from FILE *, supports compressed input
884 * if @filename is " " then the standard input is used
885 *
886 * Returns an I/O context or NULL in case of error
887 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000888static void *
889xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000890 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000891 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000892
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000893 if (filename == NULL)
894 return(NULL);
895
Owen Taylor3473f882001-02-23 17:55:21 +0000896 if (!strcmp(filename, "-")) {
897 fd = stdin;
898 return((void *) fd);
899 }
900
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000901 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000902#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000903 path = &filename[17];
904#else
Owen Taylor3473f882001-02-23 17:55:21 +0000905 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000906#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000907 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000908#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000909 path = &filename[8];
910#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000911 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000912#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000913 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
914 /* lots of generators seems to lazy to read RFC 1738 */
915#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
916 path = &filename[6];
917#else
918 path = &filename[5];
919#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200920 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000921 path = filename;
922
923 if (path == NULL)
924 return(NULL);
925 if (!xmlCheckFilename(path))
926 return(NULL);
927
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000928#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
929 fd = xmlWrapOpen(path, 0);
930#else
931 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000932#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000933 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000934 return((void *) fd);
935}
936
937/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000938 * xmlFileOpen:
939 * @filename: the URI for matching
940 *
941 * Wrapper around xmlFileOpen_real that try it with an unescaped
942 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000943 *
944 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000945 */
946void *
947xmlFileOpen (const char *filename) {
948 char *unescaped;
949 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000950
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000951 retval = xmlFileOpen_real(filename);
952 if (retval == NULL) {
953 unescaped = xmlURIUnescapeString(filename, 0, NULL);
954 if (unescaped != NULL) {
955 retval = xmlFileOpen_real(unescaped);
956 xmlFree(unescaped);
957 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000958 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000959
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000960 return retval;
961}
962
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000963#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000964/**
Owen Taylor3473f882001-02-23 17:55:21 +0000965 * xmlFileOpenW:
966 * @filename: the URI for matching
967 *
968 * output to from FILE *,
969 * if @filename is "-" then the standard output is used
970 *
971 * Returns an I/O context or NULL in case of error
972 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000973static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000974xmlFileOpenW (const char *filename) {
975 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000976 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000977
978 if (!strcmp(filename, "-")) {
979 fd = stdout;
980 return((void *) fd);
981 }
982
Daniel Veillardf4862f02002-09-10 11:13:43 +0000983 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000984#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000985 path = &filename[17];
986#else
Owen Taylor3473f882001-02-23 17:55:21 +0000987 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000988#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000989 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000990#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000991 path = &filename[8];
992#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000993 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000994#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200995 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000996 path = filename;
997
998 if (path == NULL)
999 return(NULL);
1000
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001001#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1002 fd = xmlWrapOpen(path, 1);
1003#else
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001004 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001005#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +00001006
Daniel Veillardf7416012006-04-27 08:15:20 +00001007 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +00001008 return((void *) fd);
1009}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001010#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001011
1012/**
1013 * xmlFileRead:
1014 * @context: the I/O context
1015 * @buffer: where to drop data
1016 * @len: number of bytes to write
1017 *
1018 * Read @len bytes to @buffer from the I/O channel.
1019 *
Daniel Veillardce682bc2004-11-05 17:22:25 +00001020 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001021 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001022int
Owen Taylor3473f882001-02-23 17:55:21 +00001023xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001024 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001025 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001026 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001027 ret = fread(&buffer[0], 1, len, (FILE *) context);
1028 if (ret < 0) xmlIOErr(0, "fread()");
1029 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001030}
1031
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001032#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001033/**
1034 * xmlFileWrite:
1035 * @context: the I/O context
1036 * @buffer: where to drop data
1037 * @len: number of bytes to write
1038 *
1039 * Write @len bytes from @buffer to the I/O channel.
1040 *
1041 * Returns the number of bytes written
1042 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001043static int
Owen Taylor3473f882001-02-23 17:55:21 +00001044xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001045 int items;
1046
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001047 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001048 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001049 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001050 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001051 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001052 return(-1);
1053 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001054 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001055}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001056#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001057
1058/**
1059 * xmlFileClose:
1060 * @context: the I/O context
1061 *
1062 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001063 *
1064 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001065 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001066int
Owen Taylor3473f882001-02-23 17:55:21 +00001067xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001068 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001069 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001070
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001071 if (context == NULL)
1072 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001073 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001074 if ((fil == stdout) || (fil == stderr)) {
1075 ret = fflush(fil);
1076 if (ret < 0)
1077 xmlIOErr(0, "fflush()");
1078 return(0);
1079 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001080 if (fil == stdin)
1081 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001082 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1083 if (ret < 0)
1084 xmlIOErr(0, "fclose()");
1085 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001086}
1087
1088/**
1089 * xmlFileFlush:
1090 * @context: the I/O context
1091 *
1092 * Flush an I/O channel
1093 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001094static int
Owen Taylor3473f882001-02-23 17:55:21 +00001095xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001096 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001097
1098 if (context == NULL)
1099 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001100 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1101 if (ret < 0)
1102 xmlIOErr(0, "fflush()");
1103 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001104}
1105
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001106#ifdef LIBXML_OUTPUT_ENABLED
1107/**
1108 * xmlBufferWrite:
1109 * @context: the xmlBuffer
1110 * @buffer: the data to write
1111 * @len: number of bytes to write
1112 *
1113 * Write @len bytes from @buffer to the xml buffer
1114 *
1115 * Returns the number of bytes written
1116 */
1117static int
1118xmlBufferWrite (void * context, const char * buffer, int len) {
1119 int ret;
1120
1121 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1122 if (ret != 0)
1123 return(-1);
1124 return(len);
1125}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001126#endif
1127
Owen Taylor3473f882001-02-23 17:55:21 +00001128#ifdef HAVE_ZLIB_H
1129/************************************************************************
1130 * *
1131 * I/O for compressed file accesses *
1132 * *
1133 ************************************************************************/
1134/**
1135 * xmlGzfileMatch:
1136 * @filename: the URI for matching
1137 *
1138 * input from compressed file test
1139 *
1140 * Returns 1 if matches, 0 otherwise
1141 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001142static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001143xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001144 return(1);
1145}
1146
1147/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001148 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001149 * @filename: the URI for matching
1150 *
1151 * input from compressed file open
1152 * if @filename is " " then the standard input is used
1153 *
1154 * Returns an I/O context or NULL in case of error
1155 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001156static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001157xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001158 const char *path = NULL;
1159 gzFile fd;
1160
1161 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001162 int duped_fd = dup(fileno(stdin));
1163 fd = gzdopen(duped_fd, "rb");
1164 if (fd == Z_NULL) {
1165 close(duped_fd); /* gzdOpen() does not close on failure */
1166 }
1167
Owen Taylor3473f882001-02-23 17:55:21 +00001168 return((void *) fd);
1169 }
1170
Daniel Veillardf4862f02002-09-10 11:13:43 +00001171 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001172#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001173 path = &filename[17];
1174#else
Owen Taylor3473f882001-02-23 17:55:21 +00001175 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001176#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001177 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001178#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001179 path = &filename[8];
1180#else
Owen Taylor3473f882001-02-23 17:55:21 +00001181 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001182#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001183 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001184 path = filename;
1185
1186 if (path == NULL)
1187 return(NULL);
1188 if (!xmlCheckFilename(path))
1189 return(NULL);
1190
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001191#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1192 fd = xmlWrapGzOpen(path, "rb");
1193#else
Owen Taylor3473f882001-02-23 17:55:21 +00001194 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001195#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001196 return((void *) fd);
1197}
1198
1199/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001200 * xmlGzfileOpen:
1201 * @filename: the URI for matching
1202 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001203 * Wrapper around xmlGzfileOpen if the open fais, it will
1204 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001205 */
1206static void *
1207xmlGzfileOpen (const char *filename) {
1208 char *unescaped;
1209 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001210
1211 retval = xmlGzfileOpen_real(filename);
1212 if (retval == NULL) {
1213 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1214 if (unescaped != NULL) {
1215 retval = xmlGzfileOpen_real(unescaped);
1216 }
1217 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001218 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001219 return retval;
1220}
1221
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001222#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001223/**
Owen Taylor3473f882001-02-23 17:55:21 +00001224 * xmlGzfileOpenW:
1225 * @filename: the URI for matching
1226 * @compression: the compression factor (0 - 9 included)
1227 *
1228 * input from compressed file open
1229 * if @filename is " " then the standard input is used
1230 *
1231 * Returns an I/O context or NULL in case of error
1232 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001233static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001234xmlGzfileOpenW (const char *filename, int compression) {
1235 const char *path = NULL;
1236 char mode[15];
1237 gzFile fd;
1238
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001239 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001240 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001241 int duped_fd = dup(fileno(stdout));
1242 fd = gzdopen(duped_fd, "rb");
1243 if (fd == Z_NULL) {
1244 close(duped_fd); /* gzdOpen() does not close on failure */
1245 }
1246
Owen Taylor3473f882001-02-23 17:55:21 +00001247 return((void *) fd);
1248 }
1249
Daniel Veillardf4862f02002-09-10 11:13:43 +00001250 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001251#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001252 path = &filename[17];
1253#else
Owen Taylor3473f882001-02-23 17:55:21 +00001254 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001255#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001256 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001257#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001258 path = &filename[8];
1259#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001260 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001261#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001262 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001263 path = filename;
1264
1265 if (path == NULL)
1266 return(NULL);
1267
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001268#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1269 fd = xmlWrapGzOpen(path, mode);
1270#else
Owen Taylor3473f882001-02-23 17:55:21 +00001271 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001272#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001273 return((void *) fd);
1274}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001275#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001276
1277/**
1278 * xmlGzfileRead:
1279 * @context: the I/O context
1280 * @buffer: where to drop data
1281 * @len: number of bytes to write
1282 *
1283 * Read @len bytes to @buffer from the compressed I/O channel.
1284 *
1285 * Returns the number of bytes written
1286 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001287static int
Owen Taylor3473f882001-02-23 17:55:21 +00001288xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001289 int ret;
1290
1291 ret = gzread((gzFile) context, &buffer[0], len);
1292 if (ret < 0) xmlIOErr(0, "gzread()");
1293 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001294}
1295
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001296#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001297/**
1298 * xmlGzfileWrite:
1299 * @context: the I/O context
1300 * @buffer: where to drop data
1301 * @len: number of bytes to write
1302 *
1303 * Write @len bytes from @buffer to the compressed I/O channel.
1304 *
1305 * Returns the number of bytes written
1306 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001307static int
Owen Taylor3473f882001-02-23 17:55:21 +00001308xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001309 int ret;
1310
1311 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1312 if (ret < 0) xmlIOErr(0, "gzwrite()");
1313 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001314}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001315#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001316
1317/**
1318 * xmlGzfileClose:
1319 * @context: the I/O context
1320 *
1321 * Close a compressed I/O channel
1322 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001323static int
Owen Taylor3473f882001-02-23 17:55:21 +00001324xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001325 int ret;
1326
1327 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1328 if (ret < 0) xmlIOErr(0, "gzclose()");
1329 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001330}
1331#endif /* HAVE_ZLIB_H */
1332
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001333#ifdef HAVE_LZMA_H
1334/************************************************************************
1335 * *
1336 * I/O for compressed file accesses *
1337 * *
1338 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001339#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001340/**
1341 * xmlXzfileMatch:
1342 * @filename: the URI for matching
1343 *
1344 * input from compressed file test
1345 *
1346 * Returns 1 if matches, 0 otherwise
1347 */
1348static int
1349xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1350 return(1);
1351}
1352
1353/**
1354 * xmlXzFileOpen_real:
1355 * @filename: the URI for matching
1356 *
1357 * input from compressed file open
1358 * if @filename is " " then the standard input is used
1359 *
1360 * Returns an I/O context or NULL in case of error
1361 */
1362static void *
1363xmlXzfileOpen_real (const char *filename) {
1364 const char *path = NULL;
1365 xzFile fd;
1366
1367 if (!strcmp(filename, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001368 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001369 return((void *) fd);
1370 }
1371
1372 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1373 path = &filename[16];
1374 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1375 path = &filename[7];
1376 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1377 /* lots of generators seems to lazy to read RFC 1738 */
1378 path = &filename[5];
1379 } else
1380 path = filename;
1381
1382 if (path == NULL)
1383 return(NULL);
1384 if (!xmlCheckFilename(path))
1385 return(NULL);
1386
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001387 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001388 return((void *) fd);
1389}
1390
1391/**
1392 * xmlXzfileOpen:
1393 * @filename: the URI for matching
1394 *
1395 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1396 * version of @filename, if this fails fallback to @filename
1397 *
1398 * Returns a handler or NULL in case or failure
1399 */
1400static void *
1401xmlXzfileOpen (const char *filename) {
1402 char *unescaped;
1403 void *retval;
1404
1405 retval = xmlXzfileOpen_real(filename);
1406 if (retval == NULL) {
1407 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1408 if (unescaped != NULL) {
1409 retval = xmlXzfileOpen_real(unescaped);
1410 }
1411 xmlFree(unescaped);
1412 }
1413
1414 return retval;
1415}
1416
1417/**
1418 * xmlXzfileRead:
1419 * @context: the I/O context
1420 * @buffer: where to drop data
1421 * @len: number of bytes to write
1422 *
1423 * Read @len bytes to @buffer from the compressed I/O channel.
1424 *
1425 * Returns the number of bytes written
1426 */
1427static int
1428xmlXzfileRead (void * context, char * buffer, int len) {
1429 int ret;
1430
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001431 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001432 if (ret < 0) xmlIOErr(0, "xzread()");
1433 return(ret);
1434}
1435
1436/**
1437 * xmlXzfileClose:
1438 * @context: the I/O context
1439 *
1440 * Close a compressed I/O channel
1441 */
1442static int
1443xmlXzfileClose (void * context) {
1444 int ret;
1445
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001446 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001447 if (ret < 0) xmlIOErr(0, "xzclose()");
1448 return(ret);
1449}
1450#endif /* HAVE_LZMA_H */
1451
Owen Taylor3473f882001-02-23 17:55:21 +00001452#ifdef LIBXML_HTTP_ENABLED
1453/************************************************************************
1454 * *
1455 * I/O for HTTP file accesses *
1456 * *
1457 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001458
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001459#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001460typedef struct xmlIOHTTPWriteCtxt_
1461{
1462 int compression;
1463
1464 char * uri;
1465
1466 void * doc_buff;
1467
1468} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1469
1470#ifdef HAVE_ZLIB_H
1471
1472#define DFLT_WBITS ( -15 )
1473#define DFLT_MEM_LVL ( 8 )
1474#define GZ_MAGIC1 ( 0x1f )
1475#define GZ_MAGIC2 ( 0x8b )
1476#define LXML_ZLIB_OS_CODE ( 0x03 )
1477#define INIT_HTTP_BUFF_SIZE ( 32768 )
1478#define DFLT_ZLIB_RATIO ( 5 )
1479
1480/*
1481** Data structure and functions to work with sending compressed data
1482** via HTTP.
1483*/
1484
1485typedef struct xmlZMemBuff_
1486{
1487 unsigned long size;
1488 unsigned long crc;
1489
1490 unsigned char * zbuff;
1491 z_stream zctrl;
1492
1493} xmlZMemBuff, *xmlZMemBuffPtr;
1494
1495/**
1496 * append_reverse_ulong
1497 * @buff: Compressed memory buffer
1498 * @data: Unsigned long to append
1499 *
1500 * Append a unsigned long in reverse byte order to the end of the
1501 * memory buffer.
1502 */
1503static void
1504append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1505
1506 int idx;
1507
1508 if ( buff == NULL )
1509 return;
1510
1511 /*
1512 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001513 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001514 ** support 64 bit file sizes, this code would need to be patched
1515 ** as well.
1516 */
1517
1518 for ( idx = 0; idx < 4; idx++ ) {
1519 *buff->zctrl.next_out = ( data & 0xff );
1520 data >>= 8;
1521 buff->zctrl.next_out++;
1522 }
1523
1524 return;
1525}
1526
1527/**
1528 *
1529 * xmlFreeZMemBuff
1530 * @buff: The memory buffer context to clear
1531 *
1532 * Release all the resources associated with the compressed memory buffer.
1533 */
1534static void
1535xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001536
1537#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001538 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001539#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001540
1541 if ( buff == NULL )
1542 return;
1543
1544 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001545#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001546 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001547 if ( z_err != Z_OK )
1548 xmlGenericError( xmlGenericErrorContext,
1549 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1550 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001551#else
1552 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001553#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001554
1555 xmlFree( buff );
1556 return;
1557}
1558
1559/**
1560 * xmlCreateZMemBuff
1561 *@compression: Compression value to use
1562 *
1563 * Create a memory buffer to hold the compressed XML document. The
1564 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001565 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001566 * write the document to disk. The code for the header/trailer data to
1567 * the compression is plagiarized from the zlib source files.
1568 */
1569static void *
1570xmlCreateZMemBuff( int compression ) {
1571
1572 int z_err;
1573 int hdr_lgth;
1574 xmlZMemBuffPtr buff = NULL;
1575
1576 if ( ( compression < 1 ) || ( compression > 9 ) )
1577 return ( NULL );
1578
1579 /* Create the control and data areas */
1580
1581 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1582 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001583 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001584 return ( NULL );
1585 }
1586
1587 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1588 buff->size = INIT_HTTP_BUFF_SIZE;
1589 buff->zbuff = xmlMalloc( buff->size );
1590 if ( buff->zbuff == NULL ) {
1591 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001592 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001593 return ( NULL );
1594 }
1595
1596 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1597 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1598 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001599 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001600 xmlFreeZMemBuff( buff );
1601 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001602 xmlStrPrintf(msg, 500,
1603 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1604 "Error initializing compression context. ZLIB error:",
1605 z_err );
1606 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001607 return ( NULL );
1608 }
1609
1610 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001611 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001612 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1613 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001614 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001615 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1616 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1617 buff->zctrl.avail_out = buff->size - hdr_lgth;
1618
1619 return ( buff );
1620}
1621
1622/**
1623 * xmlZMemBuffExtend
1624 * @buff: Buffer used to compress and consolidate data.
1625 * @ext_amt: Number of bytes to extend the buffer.
1626 *
1627 * Extend the internal buffer used to store the compressed data by the
1628 * specified amount.
1629 *
1630 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1631 * the original buffer still exists at the original size.
1632 */
1633static int
1634xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1635
1636 int rc = -1;
1637 size_t new_size;
1638 size_t cur_used;
1639
1640 unsigned char * tmp_ptr = NULL;
1641
1642 if ( buff == NULL )
1643 return ( -1 );
1644
1645 else if ( ext_amt == 0 )
1646 return ( 0 );
1647
1648 cur_used = buff->zctrl.next_out - buff->zbuff;
1649 new_size = buff->size + ext_amt;
1650
1651#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001652 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001653 xmlGenericError( xmlGenericErrorContext,
1654 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1655 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001656 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001657 (cur_used - new_size ) );
1658#endif
1659
1660 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1661 if ( tmp_ptr != NULL ) {
1662 rc = 0;
1663 buff->size = new_size;
1664 buff->zbuff = tmp_ptr;
1665 buff->zctrl.next_out = tmp_ptr + cur_used;
1666 buff->zctrl.avail_out = new_size - cur_used;
1667 }
1668 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001669 xmlChar msg[500];
1670 xmlStrPrintf(msg, 500,
1671 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1672 "Allocation failure extending output buffer to",
1673 new_size );
1674 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001675 }
1676
1677 return ( rc );
1678}
1679
1680/**
1681 * xmlZMemBuffAppend
1682 * @buff: Buffer used to compress and consolidate data
1683 * @src: Uncompressed source content to append to buffer
1684 * @len: Length of source data to append to buffer
1685 *
1686 * Compress and append data to the internal buffer. The data buffer
1687 * will be expanded if needed to store the additional data.
1688 *
1689 * Returns the number of bytes appended to the buffer or -1 on error.
1690 */
1691static int
1692xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1693
1694 int z_err;
1695 size_t min_accept;
1696
1697 if ( ( buff == NULL ) || ( src == NULL ) )
1698 return ( -1 );
1699
1700 buff->zctrl.avail_in = len;
1701 buff->zctrl.next_in = (unsigned char *)src;
1702 while ( buff->zctrl.avail_in > 0 ) {
1703 /*
1704 ** Extend the buffer prior to deflate call if a reasonable amount
1705 ** of output buffer space is not available.
1706 */
1707 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1708 if ( buff->zctrl.avail_out <= min_accept ) {
1709 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1710 return ( -1 );
1711 }
1712
1713 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1714 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001715 xmlChar msg[500];
1716 xmlStrPrintf(msg, 500,
1717 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001718 "Compression error while appending",
1719 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001720 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001721 return ( -1 );
1722 }
1723 }
1724
1725 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1726
1727 return ( len );
1728}
1729
1730/**
1731 * xmlZMemBuffGetContent
1732 * @buff: Compressed memory content buffer
1733 * @data_ref: Pointer reference to point to compressed content
1734 *
1735 * Flushes the compression buffers, appends gzip file trailers and
1736 * returns the compressed content and length of the compressed data.
1737 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1738 *
1739 * Returns the length of the compressed data or -1 on error.
1740 */
1741static int
1742xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1743
1744 int zlgth = -1;
1745 int z_err;
1746
1747 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1748 return ( -1 );
1749
1750 /* Need to loop until compression output buffers are flushed */
1751
1752 do
1753 {
1754 z_err = deflate( &buff->zctrl, Z_FINISH );
1755 if ( z_err == Z_OK ) {
1756 /* In this case Z_OK means more buffer space needed */
1757
1758 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1759 return ( -1 );
1760 }
1761 }
1762 while ( z_err == Z_OK );
1763
1764 /* If the compression state is not Z_STREAM_END, some error occurred */
1765
1766 if ( z_err == Z_STREAM_END ) {
1767
1768 /* Need to append the gzip data trailer */
1769
1770 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1771 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1772 return ( -1 );
1773 }
1774
1775 /*
1776 ** For whatever reason, the CRC and length data are pushed out
1777 ** in reverse byte order. So a memcpy can't be used here.
1778 */
1779
1780 append_reverse_ulong( buff, buff->crc );
1781 append_reverse_ulong( buff, buff->zctrl.total_in );
1782
1783 zlgth = buff->zctrl.next_out - buff->zbuff;
1784 *data_ref = (char *)buff->zbuff;
1785 }
1786
Daniel Veillard05d987b2003-10-08 11:54:57 +00001787 else {
1788 xmlChar msg[500];
1789 xmlStrPrintf(msg, 500,
1790 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1791 "Error flushing zlib buffers. Error code", z_err );
1792 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1793 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001794
Daniel Veillardf012a642001-07-23 19:10:52 +00001795 return ( zlgth );
1796}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001797#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001798#endif /* HAVE_ZLIB_H */
1799
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001800#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001801/**
1802 * xmlFreeHTTPWriteCtxt
1803 * @ctxt: Context to cleanup
1804 *
1805 * Free allocated memory and reclaim system resources.
1806 *
1807 * No return value.
1808 */
1809static void
1810xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1811{
1812 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001813 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001814
1815 if ( ctxt->doc_buff != NULL ) {
1816
1817#ifdef HAVE_ZLIB_H
1818 if ( ctxt->compression > 0 ) {
1819 xmlFreeZMemBuff( ctxt->doc_buff );
1820 }
1821 else
1822#endif
1823 {
1824 xmlOutputBufferClose( ctxt->doc_buff );
1825 }
1826 }
1827
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001828 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001829 return;
1830}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001831#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001832
1833
Owen Taylor3473f882001-02-23 17:55:21 +00001834/**
1835 * xmlIOHTTPMatch:
1836 * @filename: the URI for matching
1837 *
1838 * check if the URI matches an HTTP one
1839 *
1840 * Returns 1 if matches, 0 otherwise
1841 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001842int
Owen Taylor3473f882001-02-23 17:55:21 +00001843xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001844 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001845 return(1);
1846 return(0);
1847}
1848
1849/**
1850 * xmlIOHTTPOpen:
1851 * @filename: the URI for matching
1852 *
1853 * open an HTTP I/O channel
1854 *
1855 * Returns an I/O context or NULL in case of error
1856 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001857void *
Owen Taylor3473f882001-02-23 17:55:21 +00001858xmlIOHTTPOpen (const char *filename) {
1859 return(xmlNanoHTTPOpen(filename, NULL));
1860}
1861
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001862#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001863/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001864 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001865 * @post_uri: The destination URI for the document
1866 * @compression: The compression desired for the document.
1867 *
1868 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1869 * request. Non-static as is called from the output buffer creation routine.
1870 *
1871 * Returns an I/O context or NULL in case of error.
1872 */
1873
1874void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001875xmlIOHTTPOpenW(const char *post_uri, int compression)
1876{
Daniel Veillardf012a642001-07-23 19:10:52 +00001877
Daniel Veillard572577e2002-01-18 16:23:55 +00001878 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001879
Daniel Veillard572577e2002-01-18 16:23:55 +00001880 if (post_uri == NULL)
1881 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001882
Daniel Veillard572577e2002-01-18 16:23:55 +00001883 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1884 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001885 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001886 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001887 }
1888
Daniel Veillard572577e2002-01-18 16:23:55 +00001889 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001890
Daniel Veillard572577e2002-01-18 16:23:55 +00001891 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1892 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001893 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001894 xmlFreeHTTPWriteCtxt(ctxt);
1895 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001896 }
1897
1898 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001899 * ** Since the document length is required for an HTTP post,
1900 * ** need to put the document into a buffer. A memory buffer
1901 * ** is being used to avoid pushing the data to disk and back.
1902 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001903
1904#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001905 if ((compression > 0) && (compression <= 9)) {
1906
1907 ctxt->compression = compression;
1908 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1909 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001910#endif
1911 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001912 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001913
Daniel Veillardda3fee42008-09-01 13:08:57 +00001914 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001915 }
1916
Daniel Veillard572577e2002-01-18 16:23:55 +00001917 if (ctxt->doc_buff == NULL) {
1918 xmlFreeHTTPWriteCtxt(ctxt);
1919 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001920 }
1921
Daniel Veillard572577e2002-01-18 16:23:55 +00001922 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001923}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001924#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001925
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001926#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001927/**
1928 * xmlIOHTTPDfltOpenW
1929 * @post_uri: The destination URI for this document.
1930 *
1931 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1932 * HTTP post command. This function should generally not be used as
1933 * the open callback is short circuited in xmlOutputBufferCreateFile.
1934 *
1935 * Returns a pointer to the new IO context.
1936 */
1937static void *
1938xmlIOHTTPDfltOpenW( const char * post_uri ) {
1939 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1940}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001941#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001942
1943/**
Owen Taylor3473f882001-02-23 17:55:21 +00001944 * xmlIOHTTPRead:
1945 * @context: the I/O context
1946 * @buffer: where to drop data
1947 * @len: number of bytes to write
1948 *
1949 * Read @len bytes to @buffer from the I/O channel.
1950 *
1951 * Returns the number of bytes written
1952 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001953int
Owen Taylor3473f882001-02-23 17:55:21 +00001954xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001955 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001956 return(xmlNanoHTTPRead(context, &buffer[0], len));
1957}
1958
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001959#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001960/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001961 * xmlIOHTTPWrite
1962 * @context: previously opened writing context
1963 * @buffer: data to output to temporary buffer
1964 * @len: bytes to output
1965 *
1966 * Collect data from memory buffer into a temporary file for later
1967 * processing.
1968 *
1969 * Returns number of bytes written.
1970 */
1971
1972static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001973xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001974
1975 xmlIOHTTPWriteCtxtPtr ctxt = context;
1976
1977 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1978 return ( -1 );
1979
1980 if ( len > 0 ) {
1981
1982 /* Use gzwrite or fwrite as previously setup in the open call */
1983
1984#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001985 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001986 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1987
1988 else
1989#endif
1990 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1991
1992 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001993 xmlChar msg[500];
1994 xmlStrPrintf(msg, 500,
1995 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001996 "Error appending to internal buffer.",
1997 "Error sending document to URI",
1998 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001999 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002000 }
2001 }
2002
2003 return ( len );
2004}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002005#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002006
2007
2008/**
Owen Taylor3473f882001-02-23 17:55:21 +00002009 * xmlIOHTTPClose:
2010 * @context: the I/O context
2011 *
2012 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002013 *
2014 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002015 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002016int
Owen Taylor3473f882001-02-23 17:55:21 +00002017xmlIOHTTPClose (void * context) {
2018 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00002019 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002020}
Daniel Veillardf012a642001-07-23 19:10:52 +00002021
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002022#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002023/**
2024 * xmlIOHTTCloseWrite
2025 * @context: The I/O context
2026 * @http_mthd: The HTTP method to be used when sending the data
2027 *
2028 * Close the transmit HTTP I/O channel and actually send the data.
2029 */
2030static int
2031xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2032
2033 int close_rc = -1;
2034 int http_rtn = 0;
2035 int content_lgth = 0;
2036 xmlIOHTTPWriteCtxtPtr ctxt = context;
2037
2038 char * http_content = NULL;
2039 char * content_encoding = NULL;
2040 char * content_type = (char *) "text/xml";
2041 void * http_ctxt = NULL;
2042
2043 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2044 return ( -1 );
2045
2046 /* Retrieve the content from the appropriate buffer */
2047
2048#ifdef HAVE_ZLIB_H
2049
2050 if ( ctxt->compression > 0 ) {
2051 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2052 content_encoding = (char *) "Content-Encoding: gzip";
2053 }
2054 else
2055#endif
2056 {
2057 /* Pull the data out of the memory output buffer */
2058
2059 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002060 http_content = (char *) xmlBufContent(dctxt->buffer);
2061 content_lgth = xmlBufUse(dctxt->buffer);
Daniel Veillardf012a642001-07-23 19:10:52 +00002062 }
2063
2064 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002065 xmlChar msg[500];
2066 xmlStrPrintf(msg, 500,
2067 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2068 "Error retrieving content.\nUnable to",
2069 http_mthd, "data to URI", ctxt->uri );
2070 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002071 }
2072
2073 else {
2074
2075 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002076 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00002077 content_lgth );
2078
2079 if ( http_ctxt != NULL ) {
2080#ifdef DEBUG_HTTP
2081 /* If testing/debugging - dump reply with request content */
2082
2083 FILE * tst_file = NULL;
2084 char buffer[ 4096 ];
2085 char * dump_name = NULL;
2086 int avail;
2087
2088 xmlGenericError( xmlGenericErrorContext,
2089 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2090 http_mthd, ctxt->uri,
2091 xmlNanoHTTPReturnCode( http_ctxt ) );
2092
2093 /*
2094 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002095 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002096 ** standard error context.
2097 */
2098
2099 dump_name = tempnam( NULL, "lxml" );
2100 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002101 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002102
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002103 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002104 if ( tst_file != NULL ) {
2105 xmlGenericError( xmlGenericErrorContext,
2106 "Transmitted content saved in file: %s\n", buffer );
2107
2108 fwrite( http_content, sizeof( char ),
2109 content_lgth, tst_file );
2110 fclose( tst_file );
2111 }
2112
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002113 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002114 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002115 if ( tst_file != NULL ) {
2116 xmlGenericError( xmlGenericErrorContext,
2117 "Reply content saved in file: %s\n", buffer );
2118
2119
2120 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2121 buffer, sizeof( buffer ) )) > 0 ) {
2122
2123 fwrite( buffer, sizeof( char ), avail, tst_file );
2124 }
2125
2126 fclose( tst_file );
2127 }
2128
2129 free( dump_name );
2130 }
2131#endif /* DEBUG_HTTP */
2132
2133 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2134 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2135 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002136 else {
2137 xmlChar msg[500];
2138 xmlStrPrintf(msg, 500,
2139 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002140 http_mthd, content_lgth,
2141 "bytes to URI", ctxt->uri,
2142 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002143 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2144 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002145
2146 xmlNanoHTTPClose( http_ctxt );
2147 xmlFree( content_type );
2148 }
2149 }
2150
2151 /* Final cleanups */
2152
2153 xmlFreeHTTPWriteCtxt( ctxt );
2154
2155 return ( close_rc );
2156}
2157
2158/**
2159 * xmlIOHTTPClosePut
2160 *
2161 * @context: The I/O context
2162 *
2163 * Close the transmit HTTP I/O channel and actually send data using a PUT
2164 * HTTP method.
2165 */
2166static int
2167xmlIOHTTPClosePut( void * ctxt ) {
2168 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2169}
2170
2171
2172/**
2173 * xmlIOHTTPClosePost
2174 *
2175 * @context: The I/O context
2176 *
2177 * Close the transmit HTTP I/O channel and actually send data using a POST
2178 * HTTP method.
2179 */
2180static int
2181xmlIOHTTPClosePost( void * ctxt ) {
2182 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2183}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002184#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002185
Owen Taylor3473f882001-02-23 17:55:21 +00002186#endif /* LIBXML_HTTP_ENABLED */
2187
2188#ifdef LIBXML_FTP_ENABLED
2189/************************************************************************
2190 * *
2191 * I/O for FTP file accesses *
2192 * *
2193 ************************************************************************/
2194/**
2195 * xmlIOFTPMatch:
2196 * @filename: the URI for matching
2197 *
2198 * check if the URI matches an FTP one
2199 *
2200 * Returns 1 if matches, 0 otherwise
2201 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002202int
Owen Taylor3473f882001-02-23 17:55:21 +00002203xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002204 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002205 return(1);
2206 return(0);
2207}
2208
2209/**
2210 * xmlIOFTPOpen:
2211 * @filename: the URI for matching
2212 *
2213 * open an FTP I/O channel
2214 *
2215 * Returns an I/O context or NULL in case of error
2216 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002217void *
Owen Taylor3473f882001-02-23 17:55:21 +00002218xmlIOFTPOpen (const char *filename) {
2219 return(xmlNanoFTPOpen(filename));
2220}
2221
2222/**
2223 * xmlIOFTPRead:
2224 * @context: the I/O context
2225 * @buffer: where to drop data
2226 * @len: number of bytes to write
2227 *
2228 * Read @len bytes to @buffer from the I/O channel.
2229 *
2230 * Returns the number of bytes written
2231 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002232int
Owen Taylor3473f882001-02-23 17:55:21 +00002233xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002234 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002235 return(xmlNanoFTPRead(context, &buffer[0], len));
2236}
2237
2238/**
2239 * xmlIOFTPClose:
2240 * @context: the I/O context
2241 *
2242 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002243 *
2244 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002245 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002246int
Owen Taylor3473f882001-02-23 17:55:21 +00002247xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002248 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002249}
2250#endif /* LIBXML_FTP_ENABLED */
2251
2252
2253/**
2254 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002255 * @matchFunc: the xmlInputMatchCallback
2256 * @openFunc: the xmlInputOpenCallback
2257 * @readFunc: the xmlInputReadCallback
2258 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002259 *
2260 * Register a new set of I/O callback for handling parser input.
2261 *
2262 * Returns the registered handler number or -1 in case of error
2263 */
2264int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002265xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2266 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2267 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002268 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2269 return(-1);
2270 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002271 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2272 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2273 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2274 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002275 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002276 return(xmlInputCallbackNr++);
2277}
2278
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002279#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002280/**
2281 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002282 * @matchFunc: the xmlOutputMatchCallback
2283 * @openFunc: the xmlOutputOpenCallback
2284 * @writeFunc: the xmlOutputWriteCallback
2285 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002286 *
2287 * Register a new set of I/O callback for handling output.
2288 *
2289 * Returns the registered handler number or -1 in case of error
2290 */
2291int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002292xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2293 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2294 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002295 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002296 return(-1);
2297 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002298 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2299 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2300 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2301 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002302 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002303 return(xmlOutputCallbackNr++);
2304}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002305#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002306
2307/**
2308 * xmlRegisterDefaultInputCallbacks:
2309 *
2310 * Registers the default compiled-in I/O handlers.
2311 */
2312void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002313xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002314 if (xmlInputCallbackInitialized)
2315 return;
2316
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002317#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2318 xmlInitPlatformSpecificIo();
2319#endif
2320
Owen Taylor3473f882001-02-23 17:55:21 +00002321 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2322 xmlFileRead, xmlFileClose);
2323#ifdef HAVE_ZLIB_H
2324 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2325 xmlGzfileRead, xmlGzfileClose);
2326#endif /* HAVE_ZLIB_H */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002327#ifdef HAVE_LZMA_H
2328 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2329 xmlXzfileRead, xmlXzfileClose);
2330#endif /* HAVE_ZLIB_H */
Owen Taylor3473f882001-02-23 17:55:21 +00002331
2332#ifdef LIBXML_HTTP_ENABLED
2333 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2334 xmlIOHTTPRead, xmlIOHTTPClose);
2335#endif /* LIBXML_HTTP_ENABLED */
2336
2337#ifdef LIBXML_FTP_ENABLED
2338 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2339 xmlIOFTPRead, xmlIOFTPClose);
2340#endif /* LIBXML_FTP_ENABLED */
2341 xmlInputCallbackInitialized = 1;
2342}
2343
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002344#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002345/**
2346 * xmlRegisterDefaultOutputCallbacks:
2347 *
2348 * Registers the default compiled-in I/O handlers.
2349 */
2350void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002351xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002352 if (xmlOutputCallbackInitialized)
2353 return;
2354
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002355#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2356 xmlInitPlatformSpecificIo();
2357#endif
2358
Owen Taylor3473f882001-02-23 17:55:21 +00002359 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2360 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002361
2362#ifdef LIBXML_HTTP_ENABLED
2363 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2364 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2365#endif
2366
Owen Taylor3473f882001-02-23 17:55:21 +00002367/*********************************
2368 No way a-priori to distinguish between gzipped files from
2369 uncompressed ones except opening if existing then closing
2370 and saving with same compression ratio ... a pain.
2371
2372#ifdef HAVE_ZLIB_H
2373 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2374 xmlGzfileWrite, xmlGzfileClose);
2375#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002376
2377 Nor FTP PUT ....
2378#ifdef LIBXML_FTP_ENABLED
2379 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2380 xmlIOFTPWrite, xmlIOFTPClose);
2381#endif
2382 **********************************/
2383 xmlOutputCallbackInitialized = 1;
2384}
2385
Daniel Veillardf012a642001-07-23 19:10:52 +00002386#ifdef LIBXML_HTTP_ENABLED
2387/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002388 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002389 *
2390 * By default, libxml submits HTTP output requests using the "PUT" method.
2391 * Calling this method changes the HTTP output method to use the "POST"
2392 * method instead.
2393 *
2394 */
2395void
2396xmlRegisterHTTPPostCallbacks( void ) {
2397
2398 /* Register defaults if not done previously */
2399
2400 if ( xmlOutputCallbackInitialized == 0 )
2401 xmlRegisterDefaultOutputCallbacks( );
2402
2403 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2404 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2405 return;
2406}
2407#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002408#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002409
Owen Taylor3473f882001-02-23 17:55:21 +00002410/**
2411 * xmlAllocParserInputBuffer:
2412 * @enc: the charset encoding if known
2413 *
2414 * Create a buffered parser input for progressive parsing
2415 *
2416 * Returns the new parser input or NULL
2417 */
2418xmlParserInputBufferPtr
2419xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2420 xmlParserInputBufferPtr ret;
2421
2422 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2423 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002424 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002425 return(NULL);
2426 }
2427 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002428 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002429 if (ret->buffer == NULL) {
2430 xmlFree(ret);
2431 return(NULL);
2432 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002433 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Owen Taylor3473f882001-02-23 17:55:21 +00002434 ret->encoder = xmlGetCharEncodingHandler(enc);
2435 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002436 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002437 else
2438 ret->raw = NULL;
2439 ret->readcallback = NULL;
2440 ret->closecallback = NULL;
2441 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002442 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002443 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002444
2445 return(ret);
2446}
2447
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002448#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002449/**
2450 * xmlAllocOutputBuffer:
2451 * @encoder: the encoding converter or NULL
2452 *
2453 * Create a buffered parser output
2454 *
2455 * Returns the new parser output or NULL
2456 */
2457xmlOutputBufferPtr
2458xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2459 xmlOutputBufferPtr ret;
2460
2461 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2462 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002463 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002464 return(NULL);
2465 }
2466 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002467 ret->buffer = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00002468 if (ret->buffer == NULL) {
2469 xmlFree(ret);
2470 return(NULL);
2471 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002472
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002473 /* try to avoid a performance problem with Windows realloc() */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002474 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2475 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002476
Daniel Veillardda3fee42008-09-01 13:08:57 +00002477 ret->encoder = encoder;
2478 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002479 ret->conv = xmlBufCreateSize(4000);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002480 if (ret->conv == NULL) {
2481 xmlFree(ret);
2482 return(NULL);
2483 }
2484
2485 /*
2486 * This call is designed to initiate the encoder state
2487 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002488 xmlCharEncOutput(ret, 1);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002489 } else
2490 ret->conv = NULL;
2491 ret->writecallback = NULL;
2492 ret->closecallback = NULL;
2493 ret->context = NULL;
2494 ret->written = 0;
2495
2496 return(ret);
2497}
2498
2499/**
2500 * xmlAllocOutputBufferInternal:
2501 * @encoder: the encoding converter or NULL
2502 *
2503 * Create a buffered parser output
2504 *
2505 * Returns the new parser output or NULL
2506 */
2507xmlOutputBufferPtr
2508xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2509 xmlOutputBufferPtr ret;
2510
2511 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2512 if (ret == NULL) {
2513 xmlIOErrMemory("creating output buffer");
2514 return(NULL);
2515 }
2516 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002517 ret->buffer = xmlBufCreate();
Daniel Veillardda3fee42008-09-01 13:08:57 +00002518 if (ret->buffer == NULL) {
2519 xmlFree(ret);
2520 return(NULL);
2521 }
2522
2523
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002524 /*
2525 * For conversion buffers we use the special IO handling
2526 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002527 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002528
Owen Taylor3473f882001-02-23 17:55:21 +00002529 ret->encoder = encoder;
2530 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002531 ret->conv = xmlBufCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002532 if (ret->conv == NULL) {
2533 xmlFree(ret);
2534 return(NULL);
2535 }
2536
Owen Taylor3473f882001-02-23 17:55:21 +00002537 /*
2538 * This call is designed to initiate the encoder state
2539 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002540 xmlCharEncOutput(ret, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002541 } else
2542 ret->conv = NULL;
2543 ret->writecallback = NULL;
2544 ret->closecallback = NULL;
2545 ret->context = NULL;
2546 ret->written = 0;
2547
2548 return(ret);
2549}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002550
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002551#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002552
2553/**
2554 * xmlFreeParserInputBuffer:
2555 * @in: a buffered parser input
2556 *
2557 * Free up the memory used by a buffered parser input
2558 */
2559void
2560xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002561 if (in == NULL) return;
2562
Owen Taylor3473f882001-02-23 17:55:21 +00002563 if (in->raw) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002564 xmlBufFree(in->raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002565 in->raw = NULL;
2566 }
2567 if (in->encoder != NULL) {
2568 xmlCharEncCloseFunc(in->encoder);
2569 }
2570 if (in->closecallback != NULL) {
2571 in->closecallback(in->context);
2572 }
2573 if (in->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002574 xmlBufFree(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00002575 in->buffer = NULL;
2576 }
2577
Owen Taylor3473f882001-02-23 17:55:21 +00002578 xmlFree(in);
2579}
2580
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002581#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002582/**
2583 * xmlOutputBufferClose:
2584 * @out: a buffered output
2585 *
2586 * flushes and close the output I/O channel
2587 * and free up all the associated resources
2588 *
2589 * Returns the number of byte written or -1 in case of error.
2590 */
2591int
Daniel Veillard828ce832003-10-08 19:19:10 +00002592xmlOutputBufferClose(xmlOutputBufferPtr out)
2593{
Owen Taylor3473f882001-02-23 17:55:21 +00002594 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002595 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002596
2597 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002598 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002599 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002600 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002601 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002602 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002603 }
2604 written = out->written;
2605 if (out->conv) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002606 xmlBufFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002607 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002608 }
2609 if (out->encoder != NULL) {
2610 xmlCharEncCloseFunc(out->encoder);
2611 }
2612 if (out->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002613 xmlBufFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002614 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002615 }
2616
Daniel Veillard828ce832003-10-08 19:19:10 +00002617 if (out->error)
2618 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002619 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002620 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002621}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002622#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002623
Daniel Veillard1b243b42004-06-08 10:16:42 +00002624xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002625__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002626 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002627 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002628 void *context = NULL;
2629
2630 if (xmlInputCallbackInitialized == 0)
2631 xmlRegisterDefaultInputCallbacks();
2632
2633 if (URI == NULL) return(NULL);
2634
2635 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002636 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002637 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002638 */
2639 if (context == NULL) {
2640 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2641 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2642 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002643 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002644 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002645 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002646 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002647 }
Owen Taylor3473f882001-02-23 17:55:21 +00002648 }
2649 }
2650 if (context == NULL) {
2651 return(NULL);
2652 }
2653
2654 /*
2655 * Allocate the Input buffer front-end.
2656 */
2657 ret = xmlAllocParserInputBuffer(enc);
2658 if (ret != NULL) {
2659 ret->context = context;
2660 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2661 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002662#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002663 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2664 (strcmp(URI, "-") != 0)) {
Mark Adlera7e79f22010-01-19 16:28:48 +01002665#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2666 ret->compressed = !gzdirect(context);
2667#else
William M. Brackc07329e2003-09-08 01:57:30 +00002668 if (((z_stream *)context)->avail_in > 4) {
2669 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002670 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002671 if (gzread(context, buff4, 4) == 4) {
2672 if (strncmp(buff4, cptr, 4) == 0)
2673 ret->compressed = 0;
2674 else
2675 ret->compressed = 1;
2676 gzrewind(context);
2677 }
2678 }
Mark Adlera7e79f22010-01-19 16:28:48 +01002679#endif
William M. Brackc07329e2003-09-08 01:57:30 +00002680 }
2681#endif
Daniel Veillard63588f42013-05-10 14:01:46 +08002682#ifdef HAVE_LZMA_H
2683 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2684 (strcmp(URI, "-") != 0)) {
2685 ret->compressed = __libxml2_xzcompressed(context);
2686 }
2687#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002688 }
William M. Brack42331a92004-07-29 07:07:16 +00002689 else
2690 xmlInputCallbackTable[i].closecallback (context);
2691
Owen Taylor3473f882001-02-23 17:55:21 +00002692 return(ret);
2693}
2694
2695/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002696 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002697 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002698 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002699 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002700 * Create a buffered parser input for the progressive parsing of a file
2701 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002702 * Automatic support for ZLIB/Compress compressed document is provided
2703 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002704 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002705 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002706 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002707 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002708xmlParserInputBufferPtr
2709xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2710 if ((xmlParserInputBufferCreateFilenameValue)) {
2711 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2712 }
2713 return __xmlParserInputBufferCreateFilename(URI, enc);
2714}
2715
2716#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002717xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002718__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002719 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002720 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002721 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002722 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002723 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002724 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002725 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002726#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002727 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002728#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002729
Owen Taylor3473f882001-02-23 17:55:21 +00002730 if (xmlOutputCallbackInitialized == 0)
2731 xmlRegisterDefaultOutputCallbacks();
2732
2733 if (URI == NULL) return(NULL);
2734
Daniel Veillard966a31e2004-05-09 02:58:44 +00002735 puri = xmlParseURI(URI);
2736 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002737#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002738 if ((puri->scheme != NULL) &&
2739 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002740 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002741#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002742 /*
2743 * try to limit the damages of the URI unescaping code.
2744 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002745 if ((puri->scheme == NULL) ||
2746 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002747 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2748 xmlFreeURI(puri);
2749 }
Owen Taylor3473f882001-02-23 17:55:21 +00002750
2751 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002752 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002753 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002754 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002755 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002756 if (unescaped != NULL) {
2757#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002758 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002759 context = xmlGzfileOpenW(unescaped, compression);
2760 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002761 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002762 if (ret != NULL) {
2763 ret->context = context;
2764 ret->writecallback = xmlGzfileWrite;
2765 ret->closecallback = xmlGzfileClose;
2766 }
2767 xmlFree(unescaped);
2768 return(ret);
2769 }
2770 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002771#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002772 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2773 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2774 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2775#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2776 /* Need to pass compression parameter into HTTP open calls */
2777 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2778 context = xmlIOHTTPOpenW(unescaped, compression);
2779 else
2780#endif
2781 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2782 if (context != NULL)
2783 break;
2784 }
2785 }
2786 xmlFree(unescaped);
2787 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002788
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002789 /*
2790 * If this failed try with a non-escaped URI this may be a strange
2791 * filename
2792 */
2793 if (context == NULL) {
2794#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002795 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002796 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002797 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002798 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002799 if (ret != NULL) {
2800 ret->context = context;
2801 ret->writecallback = xmlGzfileWrite;
2802 ret->closecallback = xmlGzfileClose;
2803 }
2804 return(ret);
2805 }
2806 }
2807#endif
2808 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2809 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002810 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002811#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2812 /* Need to pass compression parameter into HTTP open calls */
2813 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2814 context = xmlIOHTTPOpenW(URI, compression);
2815 else
2816#endif
2817 context = xmlOutputCallbackTable[i].opencallback(URI);
2818 if (context != NULL)
2819 break;
2820 }
Owen Taylor3473f882001-02-23 17:55:21 +00002821 }
2822 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002823
Owen Taylor3473f882001-02-23 17:55:21 +00002824 if (context == NULL) {
2825 return(NULL);
2826 }
2827
2828 /*
2829 * Allocate the Output buffer front-end.
2830 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002831 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002832 if (ret != NULL) {
2833 ret->context = context;
2834 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2835 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2836 }
2837 return(ret);
2838}
Daniel Veillard0335a842004-06-02 16:18:40 +00002839
2840/**
2841 * xmlOutputBufferCreateFilename:
2842 * @URI: a C string containing the URI or filename
2843 * @encoder: the encoding converter or NULL
2844 * @compression: the compression ration (0 none, 9 max).
2845 *
2846 * Create a buffered output for the progressive saving of a file
2847 * If filename is "-' then we use stdout as the output.
2848 * Automatic support for ZLIB/Compress compressed document is provided
2849 * by default if found at compile-time.
2850 * TODO: currently if compression is set, the library only support
2851 * writing to a local file.
2852 *
2853 * Returns the new output or NULL
2854 */
2855xmlOutputBufferPtr
2856xmlOutputBufferCreateFilename(const char *URI,
2857 xmlCharEncodingHandlerPtr encoder,
2858 int compression ATTRIBUTE_UNUSED) {
2859 if ((xmlOutputBufferCreateFilenameValue)) {
2860 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2861 }
2862 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2863}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002864#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002865
2866/**
2867 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002868 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002869 * @enc: the charset encoding if known
2870 *
2871 * Create a buffered parser input for the progressive parsing of a FILE *
2872 * buffered C I/O
2873 *
2874 * Returns the new parser input or NULL
2875 */
2876xmlParserInputBufferPtr
2877xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2878 xmlParserInputBufferPtr ret;
2879
2880 if (xmlInputCallbackInitialized == 0)
2881 xmlRegisterDefaultInputCallbacks();
2882
2883 if (file == NULL) return(NULL);
2884
2885 ret = xmlAllocParserInputBuffer(enc);
2886 if (ret != NULL) {
2887 ret->context = file;
2888 ret->readcallback = xmlFileRead;
2889 ret->closecallback = xmlFileFlush;
2890 }
2891
2892 return(ret);
2893}
2894
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002895#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002896/**
2897 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002898 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002899 * @encoder: the encoding converter or NULL
2900 *
2901 * Create a buffered output for the progressive saving to a FILE *
2902 * buffered C I/O
2903 *
2904 * Returns the new parser output or NULL
2905 */
2906xmlOutputBufferPtr
2907xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2908 xmlOutputBufferPtr ret;
2909
2910 if (xmlOutputCallbackInitialized == 0)
2911 xmlRegisterDefaultOutputCallbacks();
2912
2913 if (file == NULL) return(NULL);
2914
Daniel Veillardda3fee42008-09-01 13:08:57 +00002915 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002916 if (ret != NULL) {
2917 ret->context = file;
2918 ret->writecallback = xmlFileWrite;
2919 ret->closecallback = xmlFileFlush;
2920 }
2921
2922 return(ret);
2923}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002924
2925/**
2926 * xmlOutputBufferCreateBuffer:
2927 * @buffer: a xmlBufferPtr
2928 * @encoder: the encoding converter or NULL
2929 *
2930 * Create a buffered output for the progressive saving to a xmlBuffer
2931 *
2932 * Returns the new parser output or NULL
2933 */
2934xmlOutputBufferPtr
2935xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2936 xmlCharEncodingHandlerPtr encoder) {
2937 xmlOutputBufferPtr ret;
2938
2939 if (buffer == NULL) return(NULL);
2940
Rob Richardsa44f2342005-11-09 18:03:45 +00002941 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2942 xmlBufferWrite,
2943 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002944 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002945
2946 return(ret);
2947}
2948
Daniel Veillarde258ade2012-08-06 11:16:30 +08002949/**
2950 * xmlOutputBufferGetContent:
2951 * @out: an xmlOutputBufferPtr
2952 *
2953 * Gives a pointer to the data currently held in the output buffer
2954 *
2955 * Returns a pointer to the data or NULL in case of error
2956 */
2957const xmlChar *
2958xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2959 if ((out == NULL) || (out->buffer == NULL))
2960 return(NULL);
2961
2962 return(xmlBufContent(out->buffer));
2963}
2964
2965/**
2966 * xmlOutputBufferGetSize:
2967 * @out: an xmlOutputBufferPtr
2968 *
2969 * Gives the length of the data currently held in the output buffer
2970 *
2971 * Returns 0 in case or error or no data is held, the size otherwise
2972 */
2973size_t
2974xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2975 if ((out == NULL) || (out->buffer == NULL))
2976 return(0);
2977
2978 return(xmlBufUse(out->buffer));
2979}
2980
2981
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002982#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002983
2984/**
2985 * xmlParserInputBufferCreateFd:
2986 * @fd: a file descriptor number
2987 * @enc: the charset encoding if known
2988 *
2989 * Create a buffered parser input for the progressive parsing for the input
2990 * from a file descriptor
2991 *
2992 * Returns the new parser input or NULL
2993 */
2994xmlParserInputBufferPtr
2995xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2996 xmlParserInputBufferPtr ret;
2997
2998 if (fd < 0) return(NULL);
2999
3000 ret = xmlAllocParserInputBuffer(enc);
3001 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003002 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003003 ret->readcallback = xmlFdRead;
3004 ret->closecallback = xmlFdClose;
3005 }
3006
3007 return(ret);
3008}
3009
3010/**
3011 * xmlParserInputBufferCreateMem:
3012 * @mem: the memory input
3013 * @size: the length of the memory block
3014 * @enc: the charset encoding if known
3015 *
3016 * Create a buffered parser input for the progressive parsing for the input
3017 * from a memory area.
3018 *
3019 * Returns the new parser input or NULL
3020 */
3021xmlParserInputBufferPtr
3022xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
3023 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00003024 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00003025
3026 if (size <= 0) return(NULL);
3027 if (mem == NULL) return(NULL);
3028
3029 ret = xmlAllocParserInputBuffer(enc);
3030 if (ret != NULL) {
3031 ret->context = (void *) mem;
3032 ret->readcallback = (xmlInputReadCallback) xmlNop;
3033 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003034 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00003035 if (errcode != 0) {
3036 xmlFree(ret);
3037 return(NULL);
3038 }
Owen Taylor3473f882001-02-23 17:55:21 +00003039 }
3040
3041 return(ret);
3042}
3043
3044/**
Daniel Veillard53350552003-09-18 13:35:51 +00003045 * xmlParserInputBufferCreateStatic:
3046 * @mem: the memory input
3047 * @size: the length of the memory block
3048 * @enc: the charset encoding if known
3049 *
3050 * Create a buffered parser input for the progressive parsing for the input
3051 * from an immutable memory area. This will not copy the memory area to
3052 * the buffer, but the memory is expected to be available until the end of
3053 * the parsing, this is useful for example when using mmap'ed file.
3054 *
3055 * Returns the new parser input or NULL
3056 */
3057xmlParserInputBufferPtr
3058xmlParserInputBufferCreateStatic(const char *mem, int size,
3059 xmlCharEncoding enc) {
3060 xmlParserInputBufferPtr ret;
3061
3062 if (size <= 0) return(NULL);
3063 if (mem == NULL) return(NULL);
3064
3065 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3066 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003067 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003068 return(NULL);
3069 }
3070 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003071 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003072 if (ret->buffer == NULL) {
3073 xmlFree(ret);
3074 return(NULL);
3075 }
3076 ret->encoder = xmlGetCharEncodingHandler(enc);
3077 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003078 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00003079 else
3080 ret->raw = NULL;
3081 ret->compressed = -1;
3082 ret->context = (void *) mem;
3083 ret->readcallback = NULL;
3084 ret->closecallback = NULL;
3085
3086 return(ret);
3087}
3088
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003089#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003090/**
Owen Taylor3473f882001-02-23 17:55:21 +00003091 * xmlOutputBufferCreateFd:
3092 * @fd: a file descriptor number
3093 * @encoder: the encoding converter or NULL
3094 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003095 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003096 * to a file descriptor
3097 *
3098 * Returns the new parser output or NULL
3099 */
3100xmlOutputBufferPtr
3101xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3102 xmlOutputBufferPtr ret;
3103
3104 if (fd < 0) return(NULL);
3105
Daniel Veillardda3fee42008-09-01 13:08:57 +00003106 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003107 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003108 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003109 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003110 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003111 }
3112
3113 return(ret);
3114}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003115#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003116
3117/**
3118 * xmlParserInputBufferCreateIO:
3119 * @ioread: an I/O read function
3120 * @ioclose: an I/O close function
3121 * @ioctx: an I/O handler
3122 * @enc: the charset encoding if known
3123 *
3124 * Create a buffered parser input for the progressive parsing for the input
3125 * from an I/O handler
3126 *
3127 * Returns the new parser input or NULL
3128 */
3129xmlParserInputBufferPtr
3130xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3131 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3132 xmlParserInputBufferPtr ret;
3133
3134 if (ioread == NULL) return(NULL);
3135
3136 ret = xmlAllocParserInputBuffer(enc);
3137 if (ret != NULL) {
3138 ret->context = (void *) ioctx;
3139 ret->readcallback = ioread;
3140 ret->closecallback = ioclose;
3141 }
3142
3143 return(ret);
3144}
3145
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003146#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003147/**
3148 * xmlOutputBufferCreateIO:
3149 * @iowrite: an I/O write function
3150 * @ioclose: an I/O close function
3151 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003152 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003153 *
3154 * Create a buffered output for the progressive saving
3155 * to an I/O handler
3156 *
3157 * Returns the new parser output or NULL
3158 */
3159xmlOutputBufferPtr
3160xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3161 xmlOutputCloseCallback ioclose, void *ioctx,
3162 xmlCharEncodingHandlerPtr encoder) {
3163 xmlOutputBufferPtr ret;
3164
3165 if (iowrite == NULL) return(NULL);
3166
Daniel Veillardda3fee42008-09-01 13:08:57 +00003167 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003168 if (ret != NULL) {
3169 ret->context = (void *) ioctx;
3170 ret->writecallback = iowrite;
3171 ret->closecallback = ioclose;
3172 }
3173
3174 return(ret);
3175}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003176#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003177
3178/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003179 * xmlParserInputBufferCreateFilenameDefault:
3180 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3181 *
3182 * Registers a callback for URI input file handling
3183 *
3184 * Returns the old value of the registration function
3185 */
3186xmlParserInputBufferCreateFilenameFunc
3187xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3188{
3189 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3190 if (old == NULL) {
3191 old = __xmlParserInputBufferCreateFilename;
3192 }
3193
3194 xmlParserInputBufferCreateFilenameValue = func;
3195 return(old);
3196}
3197
3198/**
3199 * xmlOutputBufferCreateFilenameDefault:
3200 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3201 *
3202 * Registers a callback for URI output file handling
3203 *
3204 * Returns the old value of the registration function
3205 */
3206xmlOutputBufferCreateFilenameFunc
3207xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3208{
3209 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3210#ifdef LIBXML_OUTPUT_ENABLED
3211 if (old == NULL) {
3212 old = __xmlOutputBufferCreateFilename;
3213 }
3214#endif
3215 xmlOutputBufferCreateFilenameValue = func;
3216 return(old);
3217}
3218
3219/**
Owen Taylor3473f882001-02-23 17:55:21 +00003220 * xmlParserInputBufferPush:
3221 * @in: a buffered parser input
3222 * @len: the size in bytes of the array.
3223 * @buf: an char array
3224 *
3225 * Push the content of the arry in the input buffer
3226 * This routine handle the I18N transcoding to internal UTF-8
3227 * This is used when operating the parser in progressive (push) mode.
3228 *
3229 * Returns the number of chars read and stored in the buffer, or -1
3230 * in case of error.
3231 */
3232int
3233xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3234 int len, const char *buf) {
3235 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003236 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003237
3238 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003239 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003240 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003241 unsigned int use;
3242
Owen Taylor3473f882001-02-23 17:55:21 +00003243 /*
3244 * Store the data in the incoming raw buffer
3245 */
3246 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003247 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003248 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003249 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003250 if (ret != 0)
3251 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003252
3253 /*
3254 * convert as much as possible to the parser reading buffer.
3255 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003256 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003257 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003258 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003259 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003260 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003261 return(-1);
3262 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003263 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003264 } else {
3265 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003266 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003267 if (ret != 0)
3268 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003269 }
3270#ifdef DEBUG_INPUT
3271 xmlGenericError(xmlGenericErrorContext,
3272 "I/O: pushed %d chars, buffer %d/%d\n",
Roumen Petrov89b6f732012-08-04 05:09:56 +03003273 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003274#endif
3275 return(nbchars);
3276}
3277
3278/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003279 * endOfInput:
3280 *
3281 * When reading from an Input channel indicated end of file or error
3282 * don't reread from it again.
3283 */
3284static int
3285endOfInput (void * context ATTRIBUTE_UNUSED,
3286 char * buffer ATTRIBUTE_UNUSED,
3287 int len ATTRIBUTE_UNUSED) {
3288 return(0);
3289}
3290
3291/**
Owen Taylor3473f882001-02-23 17:55:21 +00003292 * xmlParserInputBufferGrow:
3293 * @in: a buffered parser input
3294 * @len: indicative value of the amount of chars to read
3295 *
3296 * Grow up the content of the input buffer, the old data are preserved
3297 * This routine handle the I18N transcoding to internal UTF-8
3298 * This routine is used when operating the parser in normal (pull) mode
3299 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003300 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003301 * onto in->buffer or in->raw
3302 *
3303 * Returns the number of chars read and stored in the buffer, or -1
3304 * in case of error.
3305 */
3306int
3307xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3308 char *buffer = NULL;
3309 int res = 0;
3310 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003311
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003312 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003313 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003314 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003315
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003316 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003317 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003318 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003319 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003320 }
Owen Taylor3473f882001-02-23 17:55:21 +00003321
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003322 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3323 xmlIOErrMemory("growing input buffer");
3324 in->error = XML_ERR_NO_MEMORY;
3325 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003326 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003327 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003328
3329 /*
3330 * Call the read method for this I/O type.
3331 */
3332 if (in->readcallback != NULL) {
3333 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003334 if (res <= 0)
3335 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003336 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003337 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003338 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003339 return(-1);
3340 }
3341 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003342 return(-1);
3343 }
Daniel Veillard63588f42013-05-10 14:01:46 +08003344
3345 /*
3346 * try to establish compressed status of input if not done already
3347 */
3348 if (in->compressed == -1) {
3349#ifdef HAVE_LZMA_H
3350 if (in->readcallback == xmlXzfileRead)
3351 in->compressed = __libxml2_xzcompressed(in->context);
3352#endif
3353 }
3354
Owen Taylor3473f882001-02-23 17:55:21 +00003355 len = res;
3356 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003357 unsigned int use;
3358
Owen Taylor3473f882001-02-23 17:55:21 +00003359 /*
3360 * Store the data in the incoming raw buffer
3361 */
3362 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003363 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003364 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003365 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003366 if (res != 0)
3367 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003368
3369 /*
3370 * convert as much as possible to the parser reading buffer.
3371 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003372 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003373 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003374 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003375 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003376 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003377 return(-1);
3378 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003379 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003380 } else {
3381 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003382 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003383 }
3384#ifdef DEBUG_INPUT
3385 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003386 "I/O: read %d chars, buffer %d\n",
3387 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003388#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003389 return(nbchars);
3390}
3391
3392/**
3393 * xmlParserInputBufferRead:
3394 * @in: a buffered parser input
3395 * @len: indicative value of the amount of chars to read
3396 *
3397 * Refresh the content of the input buffer, the old data are considered
3398 * consumed
3399 * This routine handle the I18N transcoding to internal UTF-8
3400 *
3401 * Returns the number of chars read and stored in the buffer, or -1
3402 * in case of error.
3403 */
3404int
3405xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003406 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003407 if (in->readcallback != NULL)
3408 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003409 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003410 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003411 else
3412 return(-1);
3413}
3414
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003415#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003416/**
3417 * xmlOutputBufferWrite:
3418 * @out: a buffered parser output
3419 * @len: the size in bytes of the array.
3420 * @buf: an char array
3421 *
3422 * Write the content of the array in the output I/O buffer
3423 * This routine handle the I18N transcoding from internal UTF-8
3424 * The buffer is lossless, i.e. will store in case of partial
3425 * or delayed writes.
3426 *
3427 * Returns the number of chars immediately written, or -1
3428 * in case of error.
3429 */
3430int
3431xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3432 int nbchars = 0; /* number of chars to output to I/O */
3433 int ret; /* return from function call */
3434 int written = 0; /* number of char written to I/O so far */
3435 int chunk; /* number of byte curreent processed from buf */
3436
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003437 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003438 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003439 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003440
3441 do {
3442 chunk = len;
3443 if (chunk > 4 * MINLEN)
3444 chunk = 4 * MINLEN;
3445
3446 /*
3447 * first handle encoding stuff.
3448 */
3449 if (out->encoder != NULL) {
3450 /*
3451 * Store the data in the incoming raw buffer
3452 */
3453 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003454 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003455 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003456 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003457 if (ret != 0)
3458 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003459
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003460 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003461 goto done;
3462
3463 /*
3464 * convert as much as possible to the parser reading buffer.
3465 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003466 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003467 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003468 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003469 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003470 return(-1);
3471 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003472 nbchars = xmlBufUse(out->conv);
Owen Taylor3473f882001-02-23 17:55:21 +00003473 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003474 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003475 if (ret != 0)
3476 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003477 nbchars = xmlBufUse(out->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003478 }
3479 buf += chunk;
3480 len -= chunk;
3481
3482 if ((nbchars < MINLEN) && (len <= 0))
3483 goto done;
3484
3485 if (out->writecallback) {
3486 /*
3487 * second write the stuff to the I/O channel
3488 */
3489 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003490 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003491 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003492 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003493 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003494 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003495 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003496 (const char *)xmlBufContent(out->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003497 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003498 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003499 }
3500 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003501 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003502 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003503 return(ret);
3504 }
3505 out->written += ret;
3506 }
3507 written += nbchars;
3508 } while (len > 0);
3509
3510done:
3511#ifdef DEBUG_INPUT
3512 xmlGenericError(xmlGenericErrorContext,
3513 "I/O: wrote %d chars\n", written);
3514#endif
3515 return(written);
3516}
3517
3518/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003519 * xmlEscapeContent:
3520 * @out: a pointer to an array of bytes to store the result
3521 * @outlen: the length of @out
3522 * @in: a pointer to an array of unescaped UTF-8 bytes
3523 * @inlen: the length of @in
3524 *
3525 * Take a block of UTF-8 chars in and escape them.
3526 * Returns 0 if success, or -1 otherwise
3527 * The value of @inlen after return is the number of octets consumed
3528 * if the return value is positive, else unpredictable.
3529 * The value of @outlen after return is the number of octets consumed.
3530 */
3531static int
3532xmlEscapeContent(unsigned char* out, int *outlen,
3533 const xmlChar* in, int *inlen) {
3534 unsigned char* outstart = out;
3535 const unsigned char* base = in;
3536 unsigned char* outend = out + *outlen;
3537 const unsigned char* inend;
3538
3539 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003540
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003541 while ((in < inend) && (out < outend)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003542 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003543 if (outend - out < 4) break;
3544 *out++ = '&';
3545 *out++ = 'l';
3546 *out++ = 't';
3547 *out++ = ';';
3548 } else if (*in == '>') {
3549 if (outend - out < 4) break;
3550 *out++ = '&';
3551 *out++ = 'g';
3552 *out++ = 't';
3553 *out++ = ';';
3554 } else if (*in == '&') {
3555 if (outend - out < 5) break;
3556 *out++ = '&';
3557 *out++ = 'a';
3558 *out++ = 'm';
3559 *out++ = 'p';
3560 *out++ = ';';
3561 } else if (*in == '\r') {
3562 if (outend - out < 5) break;
3563 *out++ = '&';
3564 *out++ = '#';
3565 *out++ = '1';
3566 *out++ = '3';
3567 *out++ = ';';
3568 } else {
3569 *out++ = (unsigned char) *in;
3570 }
3571 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003572 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003573 *outlen = out - outstart;
3574 *inlen = in - base;
3575 return(0);
3576}
3577
3578/**
3579 * xmlOutputBufferWriteEscape:
3580 * @out: a buffered parser output
3581 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003582 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003583 *
3584 * Write the content of the string in the output I/O buffer
3585 * This routine escapes the caracters and then handle the I18N
3586 * transcoding from internal UTF-8
3587 * The buffer is lossless, i.e. will store in case of partial
3588 * or delayed writes.
3589 *
3590 * Returns the number of chars immediately written, or -1
3591 * in case of error.
3592 */
3593int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003594xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3595 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003596 int nbchars = 0; /* number of chars to output to I/O */
3597 int ret; /* return from function call */
3598 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003599 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003600 int chunk; /* number of byte currently processed from str */
3601 int len; /* number of bytes in str */
3602 int cons; /* byte from str consumed */
3603
Daniel Veillardce244ad2004-11-05 10:03:46 +00003604 if ((out == NULL) || (out->error) || (str == NULL) ||
3605 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003606 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3607 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003608 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003609 if (len < 0) return(0);
3610 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003611 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003612
3613 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003614 oldwritten = written;
3615
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003616 /*
3617 * how many bytes to consume and how many bytes to store.
3618 */
3619 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003620 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003621
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003622 /*
3623 * make sure we have enough room to save first, if this is
3624 * not the case force a flush, but make sure we stay in the loop
3625 */
3626 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003627 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003628 return(-1);
3629 oldwritten = -1;
3630 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003631 }
3632
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003633 /*
3634 * first handle encoding stuff.
3635 */
3636 if (out->encoder != NULL) {
3637 /*
3638 * Store the data in the incoming raw buffer
3639 */
3640 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003641 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003642 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003643 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003644 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003645 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003646 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003647 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003648
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003649 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003650 goto done;
3651
3652 /*
3653 * convert as much as possible to the output buffer.
3654 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003655 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003656 if ((ret < 0) && (ret != -3)) {
3657 xmlIOErr(XML_IO_ENCODER, NULL);
3658 out->error = XML_IO_ENCODER;
3659 return(-1);
3660 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003661 nbchars = xmlBufUse(out->conv);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003662 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003663 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003664 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003665 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003666 xmlBufAddLen(out->buffer, chunk);
3667 nbchars = xmlBufUse(out->buffer);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003668 }
3669 str += cons;
3670 len -= cons;
3671
3672 if ((nbchars < MINLEN) && (len <= 0))
3673 goto done;
3674
3675 if (out->writecallback) {
3676 /*
3677 * second write the stuff to the I/O channel
3678 */
3679 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003680 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003681 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003682 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003683 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003684 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003685 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003686 (const char *)xmlBufContent(out->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003687 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003688 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003689 }
3690 if (ret < 0) {
3691 xmlIOErr(XML_IO_WRITE, NULL);
3692 out->error = XML_IO_WRITE;
3693 return(ret);
3694 }
3695 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003696 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3697 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003698 }
3699 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003700 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003701
3702done:
3703#ifdef DEBUG_INPUT
3704 xmlGenericError(xmlGenericErrorContext,
3705 "I/O: wrote %d chars\n", written);
3706#endif
3707 return(written);
3708}
3709
3710/**
Owen Taylor3473f882001-02-23 17:55:21 +00003711 * xmlOutputBufferWriteString:
3712 * @out: a buffered parser output
3713 * @str: a zero terminated C string
3714 *
3715 * Write the content of the string in the output I/O buffer
3716 * This routine handle the I18N transcoding from internal UTF-8
3717 * The buffer is lossless, i.e. will store in case of partial
3718 * or delayed writes.
3719 *
3720 * Returns the number of chars immediately written, or -1
3721 * in case of error.
3722 */
3723int
3724xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3725 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003726
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003727 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003728 if (str == NULL)
3729 return(-1);
3730 len = strlen(str);
3731
3732 if (len > 0)
3733 return(xmlOutputBufferWrite(out, len, str));
3734 return(len);
3735}
3736
3737/**
3738 * xmlOutputBufferFlush:
3739 * @out: a buffered output
3740 *
3741 * flushes the output I/O channel
3742 *
3743 * Returns the number of byte written or -1 in case of error.
3744 */
3745int
3746xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3747 int nbchars = 0, ret = 0;
3748
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003749 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003750 /*
3751 * first handle encoding stuff.
3752 */
3753 if ((out->conv != NULL) && (out->encoder != NULL)) {
3754 /*
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003755 * convert as much as possible to the parser output buffer.
Owen Taylor3473f882001-02-23 17:55:21 +00003756 */
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003757 do {
3758 nbchars = xmlCharEncOutput(out, 0);
3759 if (nbchars < 0) {
3760 xmlIOErr(XML_IO_ENCODER, NULL);
3761 out->error = XML_IO_ENCODER;
3762 return(-1);
3763 }
3764 } while (nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003765 }
3766
3767 /*
3768 * second flush the stuff to the I/O channel
3769 */
3770 if ((out->conv != NULL) && (out->encoder != NULL) &&
3771 (out->writecallback != NULL)) {
3772 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003773 (const char *)xmlBufContent(out->conv),
3774 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003775 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003776 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003777 } else if (out->writecallback != NULL) {
3778 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003779 (const char *)xmlBufContent(out->buffer),
3780 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003781 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003782 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003783 }
3784 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003785 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003786 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003787 return(ret);
3788 }
3789 out->written += ret;
3790
3791#ifdef DEBUG_INPUT
3792 xmlGenericError(xmlGenericErrorContext,
3793 "I/O: flushed %d chars\n", ret);
3794#endif
3795 return(ret);
3796}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003797#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003798
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003799/**
Owen Taylor3473f882001-02-23 17:55:21 +00003800 * xmlParserGetDirectory:
3801 * @filename: the path to a file
3802 *
3803 * lookup the directory for that file
3804 *
3805 * Returns a new allocated string containing the directory, or NULL.
3806 */
3807char *
3808xmlParserGetDirectory(const char *filename) {
3809 char *ret = NULL;
3810 char dir[1024];
3811 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003812
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003813#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3814 return NULL;
3815#endif
3816
Owen Taylor3473f882001-02-23 17:55:21 +00003817 if (xmlInputCallbackInitialized == 0)
3818 xmlRegisterDefaultInputCallbacks();
3819
3820 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003821
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003822#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003823# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3824#else
3825# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003826#endif
3827
3828 strncpy(dir, filename, 1023);
3829 dir[1023] = 0;
3830 cur = &dir[strlen(dir)];
3831 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003832 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003833 cur --;
3834 }
Rob Richardsf779da32007-08-14 09:41:21 +00003835 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003836 if (cur == dir) dir[1] = 0;
3837 else *cur = 0;
3838 ret = xmlMemStrdup(dir);
3839 } else {
3840 if (getcwd(dir, 1024) != NULL) {
3841 dir[1023] = 0;
3842 ret = xmlMemStrdup(dir);
3843 }
3844 }
3845 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003846#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003847}
3848
3849/****************************************************************
3850 * *
3851 * External entities loading *
3852 * *
3853 ****************************************************************/
3854
Daniel Veillarda840b692003-10-19 13:35:37 +00003855/**
3856 * xmlCheckHTTPInput:
3857 * @ctxt: an XML parser context
3858 * @ret: an XML parser input
3859 *
3860 * Check an input in case it was created from an HTTP stream, in that
3861 * case it will handle encoding and update of the base URL in case of
3862 * redirection. It also checks for HTTP errors in which case the input
3863 * is cleanly freed up and an appropriate error is raised in context
3864 *
3865 * Returns the input or NULL in case of HTTP error.
3866 */
3867xmlParserInputPtr
3868xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3869#ifdef LIBXML_HTTP_ENABLED
3870 if ((ret != NULL) && (ret->buf != NULL) &&
3871 (ret->buf->readcallback == xmlIOHTTPRead) &&
3872 (ret->buf->context != NULL)) {
3873 const char *encoding;
3874 const char *redir;
3875 const char *mime;
3876 int code;
3877
3878 code = xmlNanoHTTPReturnCode(ret->buf->context);
3879 if (code >= 400) {
3880 /* fatal error */
3881 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003882 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003883 (const char *) ret->filename);
3884 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003885 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003886 xmlFreeInputStream(ret);
3887 ret = NULL;
3888 } else {
3889
3890 mime = xmlNanoHTTPMimeType(ret->buf->context);
3891 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3892 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3893 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3894 if (encoding != NULL) {
3895 xmlCharEncodingHandlerPtr handler;
3896
3897 handler = xmlFindCharEncodingHandler(encoding);
3898 if (handler != NULL) {
3899 xmlSwitchInputEncoding(ctxt, ret, handler);
3900 } else {
3901 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3902 "Unknown encoding %s",
3903 BAD_CAST encoding, NULL);
3904 }
3905 if (ret->encoding == NULL)
3906 ret->encoding = xmlStrdup(BAD_CAST encoding);
3907 }
3908#if 0
3909 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3910#endif
3911 }
3912 redir = xmlNanoHTTPRedir(ret->buf->context);
3913 if (redir != NULL) {
3914 if (ret->filename != NULL)
3915 xmlFree((xmlChar *) ret->filename);
3916 if (ret->directory != NULL) {
3917 xmlFree((xmlChar *) ret->directory);
3918 ret->directory = NULL;
3919 }
3920 ret->filename =
3921 (char *) xmlStrdup((const xmlChar *) redir);
3922 }
3923 }
3924 }
3925#endif
3926 return(ret);
3927}
3928
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003929static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003930 const char *path;
3931
3932 if (URL == NULL)
3933 return(0);
3934
Daniel Veillardf4862f02002-09-10 11:13:43 +00003935 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003936#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003937 path = &URL[17];
3938#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003939 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003940#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003941 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003942#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003943 path = &URL[8];
3944#else
3945 path = &URL[7];
3946#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003947 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003948 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003949
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003950 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003951}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003952
Daniel Veillardad4e2962006-09-21 08:36:38 +00003953#ifdef LIBXML_CATALOG_ENABLED
3954
3955/**
3956 * xmlResolveResourceFromCatalog:
3957 * @URL: the URL for the entity to load
3958 * @ID: the System ID for the entity to load
3959 * @ctxt: the context in which the entity is called or NULL
3960 *
3961 * Resolves the URL and ID against the appropriate catalog.
3962 * This function is used by xmlDefaultExternalEntityLoader and
3963 * xmlNoNetExternalEntityLoader.
3964 *
3965 * Returns a new allocated URL, or NULL.
3966 */
William M. Brack38d452a2007-05-22 16:00:06 +00003967static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003968xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3969 xmlParserCtxtPtr ctxt) {
3970 xmlChar *resource = NULL;
3971 xmlCatalogAllow pref;
3972
3973 /*
3974 * If the resource doesn't exists as a file,
3975 * try to load it from the resource pointed in the catalogs
3976 */
3977 pref = xmlCatalogGetDefaults();
3978
3979 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3980 /*
3981 * Do a local lookup
3982 */
3983 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3984 ((pref == XML_CATA_ALLOW_ALL) ||
3985 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3986 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3987 (const xmlChar *)ID,
3988 (const xmlChar *)URL);
3989 }
3990 /*
3991 * Try a global lookup
3992 */
3993 if ((resource == NULL) &&
3994 ((pref == XML_CATA_ALLOW_ALL) ||
3995 (pref == XML_CATA_ALLOW_GLOBAL))) {
3996 resource = xmlCatalogResolve((const xmlChar *)ID,
3997 (const xmlChar *)URL);
3998 }
3999 if ((resource == NULL) && (URL != NULL))
4000 resource = xmlStrdup((const xmlChar *) URL);
4001
4002 /*
4003 * TODO: do an URI lookup on the reference
4004 */
4005 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
4006 xmlChar *tmp = NULL;
4007
4008 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
4009 ((pref == XML_CATA_ALLOW_ALL) ||
4010 (pref == XML_CATA_ALLOW_DOCUMENT))) {
4011 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
4012 }
4013 if ((tmp == NULL) &&
4014 ((pref == XML_CATA_ALLOW_ALL) ||
4015 (pref == XML_CATA_ALLOW_GLOBAL))) {
4016 tmp = xmlCatalogResolveURI(resource);
4017 }
4018
4019 if (tmp != NULL) {
4020 xmlFree(resource);
4021 resource = tmp;
4022 }
4023 }
4024 }
4025
4026 return resource;
4027}
4028
4029#endif
4030
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004031/**
Owen Taylor3473f882001-02-23 17:55:21 +00004032 * xmlDefaultExternalEntityLoader:
4033 * @URL: the URL for the entity to load
4034 * @ID: the System ID for the entity to load
4035 * @ctxt: the context in which the entity is called or NULL
4036 *
4037 * By default we don't load external entitites, yet.
4038 *
4039 * Returns a new allocated xmlParserInputPtr, or NULL.
4040 */
Daniel Veillarda840b692003-10-19 13:35:37 +00004041static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00004042xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00004043 xmlParserCtxtPtr ctxt)
4044{
Owen Taylor3473f882001-02-23 17:55:21 +00004045 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00004046 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00004047
Owen Taylor3473f882001-02-23 17:55:21 +00004048#ifdef DEBUG_EXTERNAL_ENTITIES
4049 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00004050 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004051#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00004052 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
4053 int options = ctxt->options;
4054
4055 ctxt->options -= XML_PARSE_NONET;
4056 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4057 ctxt->options = options;
4058 return(ret);
4059 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00004060#ifdef LIBXML_CATALOG_ENABLED
4061 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004062#endif
4063
4064 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004065 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004066
4067 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004068 if (ID == NULL)
4069 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004070 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004071 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004072 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004073 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004074 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004075 xmlFree(resource);
4076 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004077}
4078
4079static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4080 xmlDefaultExternalEntityLoader;
4081
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004082/**
Owen Taylor3473f882001-02-23 17:55:21 +00004083 * xmlSetExternalEntityLoader:
4084 * @f: the new entity resolver function
4085 *
4086 * Changes the defaultexternal entity resolver function for the application
4087 */
4088void
4089xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4090 xmlCurrentExternalEntityLoader = f;
4091}
4092
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004093/**
Owen Taylor3473f882001-02-23 17:55:21 +00004094 * xmlGetExternalEntityLoader:
4095 *
4096 * Get the default external entity resolver function for the application
4097 *
4098 * Returns the xmlExternalEntityLoader function pointer
4099 */
4100xmlExternalEntityLoader
4101xmlGetExternalEntityLoader(void) {
4102 return(xmlCurrentExternalEntityLoader);
4103}
4104
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004105/**
Owen Taylor3473f882001-02-23 17:55:21 +00004106 * xmlLoadExternalEntity:
4107 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004108 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004109 * @ctxt: the context in which the entity is called or NULL
4110 *
4111 * Load an external entity, note that the use of this function for
4112 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004113 *
4114 * Returns the xmlParserInputPtr or NULL
4115 */
4116xmlParserInputPtr
4117xmlLoadExternalEntity(const char *URL, const char *ID,
4118 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004119 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004120 char *canonicFilename;
4121 xmlParserInputPtr ret;
4122
4123 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4124 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004125 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004126 return(NULL);
4127 }
4128
4129 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4130 xmlFree(canonicFilename);
4131 return(ret);
4132 }
Owen Taylor3473f882001-02-23 17:55:21 +00004133 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4134}
4135
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004136/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004137 * *
4138 * Disabling Network access *
4139 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004140 ************************************************************************/
4141
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004142/**
4143 * xmlNoNetExternalEntityLoader:
4144 * @URL: the URL for the entity to load
4145 * @ID: the System ID for the entity to load
4146 * @ctxt: the context in which the entity is called or NULL
4147 *
4148 * A specific entity loader disabling network accesses, though still
4149 * allowing local catalog accesses for resolution.
4150 *
4151 * Returns a new allocated xmlParserInputPtr, or NULL.
4152 */
4153xmlParserInputPtr
4154xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4155 xmlParserCtxtPtr ctxt) {
4156 xmlParserInputPtr input = NULL;
4157 xmlChar *resource = NULL;
4158
4159#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004160 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004161#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004162
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004163 if (resource == NULL)
4164 resource = (xmlChar *) URL;
4165
4166 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004167 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4168 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004169 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004170 if (resource != (xmlChar *) URL)
4171 xmlFree(resource);
4172 return(NULL);
4173 }
4174 }
4175 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4176 if (resource != (xmlChar *) URL)
4177 xmlFree(resource);
4178 return(input);
4179}
4180
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004181#define bottom_xmlIO
4182#include "elfgcchack.h"