blob: d1544f3d40111984e06624840b2ffd64ceb2a17c [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, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001162 fd = gzdopen(dup(fileno(stdin)), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001163 return((void *) fd);
1164 }
1165
Daniel Veillardf4862f02002-09-10 11:13:43 +00001166 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001167#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001168 path = &filename[17];
1169#else
Owen Taylor3473f882001-02-23 17:55:21 +00001170 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001171#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001172 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001173#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001174 path = &filename[8];
1175#else
Owen Taylor3473f882001-02-23 17:55:21 +00001176 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001177#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001178 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001179 path = filename;
1180
1181 if (path == NULL)
1182 return(NULL);
1183 if (!xmlCheckFilename(path))
1184 return(NULL);
1185
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001186#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1187 fd = xmlWrapGzOpen(path, "rb");
1188#else
Owen Taylor3473f882001-02-23 17:55:21 +00001189 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001190#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001191 return((void *) fd);
1192}
1193
1194/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001195 * xmlGzfileOpen:
1196 * @filename: the URI for matching
1197 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001198 * Wrapper around xmlGzfileOpen if the open fais, it will
1199 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001200 */
1201static void *
1202xmlGzfileOpen (const char *filename) {
1203 char *unescaped;
1204 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001205
1206 retval = xmlGzfileOpen_real(filename);
1207 if (retval == NULL) {
1208 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1209 if (unescaped != NULL) {
1210 retval = xmlGzfileOpen_real(unescaped);
1211 }
1212 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001213 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001214 return retval;
1215}
1216
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001217#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001218/**
Owen Taylor3473f882001-02-23 17:55:21 +00001219 * xmlGzfileOpenW:
1220 * @filename: the URI for matching
1221 * @compression: the compression factor (0 - 9 included)
1222 *
1223 * input from compressed file open
1224 * if @filename is " " then the standard input is used
1225 *
1226 * Returns an I/O context or NULL in case of error
1227 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001228static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001229xmlGzfileOpenW (const char *filename, int compression) {
1230 const char *path = NULL;
1231 char mode[15];
1232 gzFile fd;
1233
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001234 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001235 if (!strcmp(filename, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001236 fd = gzdopen(dup(fileno(stdout)), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001237 return((void *) fd);
1238 }
1239
Daniel Veillardf4862f02002-09-10 11:13:43 +00001240 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001241#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001242 path = &filename[17];
1243#else
Owen Taylor3473f882001-02-23 17:55:21 +00001244 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001245#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001246 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001247#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001248 path = &filename[8];
1249#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001250 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001251#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001252 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001253 path = filename;
1254
1255 if (path == NULL)
1256 return(NULL);
1257
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001258#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1259 fd = xmlWrapGzOpen(path, mode);
1260#else
Owen Taylor3473f882001-02-23 17:55:21 +00001261 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001262#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001263 return((void *) fd);
1264}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001265#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001266
1267/**
1268 * xmlGzfileRead:
1269 * @context: the I/O context
1270 * @buffer: where to drop data
1271 * @len: number of bytes to write
1272 *
1273 * Read @len bytes to @buffer from the compressed I/O channel.
1274 *
1275 * Returns the number of bytes written
1276 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001277static int
Owen Taylor3473f882001-02-23 17:55:21 +00001278xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001279 int ret;
1280
1281 ret = gzread((gzFile) context, &buffer[0], len);
1282 if (ret < 0) xmlIOErr(0, "gzread()");
1283 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001284}
1285
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001286#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001287/**
1288 * xmlGzfileWrite:
1289 * @context: the I/O context
1290 * @buffer: where to drop data
1291 * @len: number of bytes to write
1292 *
1293 * Write @len bytes from @buffer to the compressed I/O channel.
1294 *
1295 * Returns the number of bytes written
1296 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001297static int
Owen Taylor3473f882001-02-23 17:55:21 +00001298xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001299 int ret;
1300
1301 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1302 if (ret < 0) xmlIOErr(0, "gzwrite()");
1303 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001304}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001305#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001306
1307/**
1308 * xmlGzfileClose:
1309 * @context: the I/O context
1310 *
1311 * Close a compressed I/O channel
1312 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001313static int
Owen Taylor3473f882001-02-23 17:55:21 +00001314xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001315 int ret;
1316
1317 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1318 if (ret < 0) xmlIOErr(0, "gzclose()");
1319 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001320}
1321#endif /* HAVE_ZLIB_H */
1322
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001323#ifdef HAVE_LZMA_H
1324/************************************************************************
1325 * *
1326 * I/O for compressed file accesses *
1327 * *
1328 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001329#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001330/**
1331 * xmlXzfileMatch:
1332 * @filename: the URI for matching
1333 *
1334 * input from compressed file test
1335 *
1336 * Returns 1 if matches, 0 otherwise
1337 */
1338static int
1339xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1340 return(1);
1341}
1342
1343/**
1344 * xmlXzFileOpen_real:
1345 * @filename: the URI for matching
1346 *
1347 * input from compressed file open
1348 * if @filename is " " then the standard input is used
1349 *
1350 * Returns an I/O context or NULL in case of error
1351 */
1352static void *
1353xmlXzfileOpen_real (const char *filename) {
1354 const char *path = NULL;
1355 xzFile fd;
1356
1357 if (!strcmp(filename, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001358 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001359 return((void *) fd);
1360 }
1361
1362 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1363 path = &filename[16];
1364 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1365 path = &filename[7];
1366 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1367 /* lots of generators seems to lazy to read RFC 1738 */
1368 path = &filename[5];
1369 } else
1370 path = filename;
1371
1372 if (path == NULL)
1373 return(NULL);
1374 if (!xmlCheckFilename(path))
1375 return(NULL);
1376
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001377 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001378 return((void *) fd);
1379}
1380
1381/**
1382 * xmlXzfileOpen:
1383 * @filename: the URI for matching
1384 *
1385 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1386 * version of @filename, if this fails fallback to @filename
1387 *
1388 * Returns a handler or NULL in case or failure
1389 */
1390static void *
1391xmlXzfileOpen (const char *filename) {
1392 char *unescaped;
1393 void *retval;
1394
1395 retval = xmlXzfileOpen_real(filename);
1396 if (retval == NULL) {
1397 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1398 if (unescaped != NULL) {
1399 retval = xmlXzfileOpen_real(unescaped);
1400 }
1401 xmlFree(unescaped);
1402 }
1403
1404 return retval;
1405}
1406
1407/**
1408 * xmlXzfileRead:
1409 * @context: the I/O context
1410 * @buffer: where to drop data
1411 * @len: number of bytes to write
1412 *
1413 * Read @len bytes to @buffer from the compressed I/O channel.
1414 *
1415 * Returns the number of bytes written
1416 */
1417static int
1418xmlXzfileRead (void * context, char * buffer, int len) {
1419 int ret;
1420
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001421 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001422 if (ret < 0) xmlIOErr(0, "xzread()");
1423 return(ret);
1424}
1425
1426/**
1427 * xmlXzfileClose:
1428 * @context: the I/O context
1429 *
1430 * Close a compressed I/O channel
1431 */
1432static int
1433xmlXzfileClose (void * context) {
1434 int ret;
1435
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001436 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001437 if (ret < 0) xmlIOErr(0, "xzclose()");
1438 return(ret);
1439}
1440#endif /* HAVE_LZMA_H */
1441
Owen Taylor3473f882001-02-23 17:55:21 +00001442#ifdef LIBXML_HTTP_ENABLED
1443/************************************************************************
1444 * *
1445 * I/O for HTTP file accesses *
1446 * *
1447 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001448
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001449#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001450typedef struct xmlIOHTTPWriteCtxt_
1451{
1452 int compression;
1453
1454 char * uri;
1455
1456 void * doc_buff;
1457
1458} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1459
1460#ifdef HAVE_ZLIB_H
1461
1462#define DFLT_WBITS ( -15 )
1463#define DFLT_MEM_LVL ( 8 )
1464#define GZ_MAGIC1 ( 0x1f )
1465#define GZ_MAGIC2 ( 0x8b )
1466#define LXML_ZLIB_OS_CODE ( 0x03 )
1467#define INIT_HTTP_BUFF_SIZE ( 32768 )
1468#define DFLT_ZLIB_RATIO ( 5 )
1469
1470/*
1471** Data structure and functions to work with sending compressed data
1472** via HTTP.
1473*/
1474
1475typedef struct xmlZMemBuff_
1476{
1477 unsigned long size;
1478 unsigned long crc;
1479
1480 unsigned char * zbuff;
1481 z_stream zctrl;
1482
1483} xmlZMemBuff, *xmlZMemBuffPtr;
1484
1485/**
1486 * append_reverse_ulong
1487 * @buff: Compressed memory buffer
1488 * @data: Unsigned long to append
1489 *
1490 * Append a unsigned long in reverse byte order to the end of the
1491 * memory buffer.
1492 */
1493static void
1494append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1495
1496 int idx;
1497
1498 if ( buff == NULL )
1499 return;
1500
1501 /*
1502 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001503 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001504 ** support 64 bit file sizes, this code would need to be patched
1505 ** as well.
1506 */
1507
1508 for ( idx = 0; idx < 4; idx++ ) {
1509 *buff->zctrl.next_out = ( data & 0xff );
1510 data >>= 8;
1511 buff->zctrl.next_out++;
1512 }
1513
1514 return;
1515}
1516
1517/**
1518 *
1519 * xmlFreeZMemBuff
1520 * @buff: The memory buffer context to clear
1521 *
1522 * Release all the resources associated with the compressed memory buffer.
1523 */
1524static void
1525xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001526
1527#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001528 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001529#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001530
1531 if ( buff == NULL )
1532 return;
1533
1534 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001535#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001536 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001537 if ( z_err != Z_OK )
1538 xmlGenericError( xmlGenericErrorContext,
1539 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1540 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001541#else
1542 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001543#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001544
1545 xmlFree( buff );
1546 return;
1547}
1548
1549/**
1550 * xmlCreateZMemBuff
1551 *@compression: Compression value to use
1552 *
1553 * Create a memory buffer to hold the compressed XML document. The
1554 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001555 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001556 * write the document to disk. The code for the header/trailer data to
1557 * the compression is plagiarized from the zlib source files.
1558 */
1559static void *
1560xmlCreateZMemBuff( int compression ) {
1561
1562 int z_err;
1563 int hdr_lgth;
1564 xmlZMemBuffPtr buff = NULL;
1565
1566 if ( ( compression < 1 ) || ( compression > 9 ) )
1567 return ( NULL );
1568
1569 /* Create the control and data areas */
1570
1571 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1572 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001573 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001574 return ( NULL );
1575 }
1576
1577 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1578 buff->size = INIT_HTTP_BUFF_SIZE;
1579 buff->zbuff = xmlMalloc( buff->size );
1580 if ( buff->zbuff == NULL ) {
1581 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001582 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001583 return ( NULL );
1584 }
1585
1586 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1587 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1588 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001589 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001590 xmlFreeZMemBuff( buff );
1591 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001592 xmlStrPrintf(msg, 500,
1593 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1594 "Error initializing compression context. ZLIB error:",
1595 z_err );
1596 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001597 return ( NULL );
1598 }
1599
1600 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001601 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001602 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1603 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001604 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001605 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1606 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1607 buff->zctrl.avail_out = buff->size - hdr_lgth;
1608
1609 return ( buff );
1610}
1611
1612/**
1613 * xmlZMemBuffExtend
1614 * @buff: Buffer used to compress and consolidate data.
1615 * @ext_amt: Number of bytes to extend the buffer.
1616 *
1617 * Extend the internal buffer used to store the compressed data by the
1618 * specified amount.
1619 *
1620 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1621 * the original buffer still exists at the original size.
1622 */
1623static int
1624xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1625
1626 int rc = -1;
1627 size_t new_size;
1628 size_t cur_used;
1629
1630 unsigned char * tmp_ptr = NULL;
1631
1632 if ( buff == NULL )
1633 return ( -1 );
1634
1635 else if ( ext_amt == 0 )
1636 return ( 0 );
1637
1638 cur_used = buff->zctrl.next_out - buff->zbuff;
1639 new_size = buff->size + ext_amt;
1640
1641#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001642 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001643 xmlGenericError( xmlGenericErrorContext,
1644 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1645 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001646 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001647 (cur_used - new_size ) );
1648#endif
1649
1650 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1651 if ( tmp_ptr != NULL ) {
1652 rc = 0;
1653 buff->size = new_size;
1654 buff->zbuff = tmp_ptr;
1655 buff->zctrl.next_out = tmp_ptr + cur_used;
1656 buff->zctrl.avail_out = new_size - cur_used;
1657 }
1658 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001659 xmlChar msg[500];
1660 xmlStrPrintf(msg, 500,
1661 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1662 "Allocation failure extending output buffer to",
1663 new_size );
1664 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001665 }
1666
1667 return ( rc );
1668}
1669
1670/**
1671 * xmlZMemBuffAppend
1672 * @buff: Buffer used to compress and consolidate data
1673 * @src: Uncompressed source content to append to buffer
1674 * @len: Length of source data to append to buffer
1675 *
1676 * Compress and append data to the internal buffer. The data buffer
1677 * will be expanded if needed to store the additional data.
1678 *
1679 * Returns the number of bytes appended to the buffer or -1 on error.
1680 */
1681static int
1682xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1683
1684 int z_err;
1685 size_t min_accept;
1686
1687 if ( ( buff == NULL ) || ( src == NULL ) )
1688 return ( -1 );
1689
1690 buff->zctrl.avail_in = len;
1691 buff->zctrl.next_in = (unsigned char *)src;
1692 while ( buff->zctrl.avail_in > 0 ) {
1693 /*
1694 ** Extend the buffer prior to deflate call if a reasonable amount
1695 ** of output buffer space is not available.
1696 */
1697 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1698 if ( buff->zctrl.avail_out <= min_accept ) {
1699 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1700 return ( -1 );
1701 }
1702
1703 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1704 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001705 xmlChar msg[500];
1706 xmlStrPrintf(msg, 500,
1707 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001708 "Compression error while appending",
1709 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001710 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001711 return ( -1 );
1712 }
1713 }
1714
1715 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1716
1717 return ( len );
1718}
1719
1720/**
1721 * xmlZMemBuffGetContent
1722 * @buff: Compressed memory content buffer
1723 * @data_ref: Pointer reference to point to compressed content
1724 *
1725 * Flushes the compression buffers, appends gzip file trailers and
1726 * returns the compressed content and length of the compressed data.
1727 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1728 *
1729 * Returns the length of the compressed data or -1 on error.
1730 */
1731static int
1732xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1733
1734 int zlgth = -1;
1735 int z_err;
1736
1737 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1738 return ( -1 );
1739
1740 /* Need to loop until compression output buffers are flushed */
1741
1742 do
1743 {
1744 z_err = deflate( &buff->zctrl, Z_FINISH );
1745 if ( z_err == Z_OK ) {
1746 /* In this case Z_OK means more buffer space needed */
1747
1748 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1749 return ( -1 );
1750 }
1751 }
1752 while ( z_err == Z_OK );
1753
1754 /* If the compression state is not Z_STREAM_END, some error occurred */
1755
1756 if ( z_err == Z_STREAM_END ) {
1757
1758 /* Need to append the gzip data trailer */
1759
1760 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1761 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1762 return ( -1 );
1763 }
1764
1765 /*
1766 ** For whatever reason, the CRC and length data are pushed out
1767 ** in reverse byte order. So a memcpy can't be used here.
1768 */
1769
1770 append_reverse_ulong( buff, buff->crc );
1771 append_reverse_ulong( buff, buff->zctrl.total_in );
1772
1773 zlgth = buff->zctrl.next_out - buff->zbuff;
1774 *data_ref = (char *)buff->zbuff;
1775 }
1776
Daniel Veillard05d987b2003-10-08 11:54:57 +00001777 else {
1778 xmlChar msg[500];
1779 xmlStrPrintf(msg, 500,
1780 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1781 "Error flushing zlib buffers. Error code", z_err );
1782 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1783 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001784
Daniel Veillardf012a642001-07-23 19:10:52 +00001785 return ( zlgth );
1786}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001787#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001788#endif /* HAVE_ZLIB_H */
1789
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001790#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001791/**
1792 * xmlFreeHTTPWriteCtxt
1793 * @ctxt: Context to cleanup
1794 *
1795 * Free allocated memory and reclaim system resources.
1796 *
1797 * No return value.
1798 */
1799static void
1800xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1801{
1802 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001803 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001804
1805 if ( ctxt->doc_buff != NULL ) {
1806
1807#ifdef HAVE_ZLIB_H
1808 if ( ctxt->compression > 0 ) {
1809 xmlFreeZMemBuff( ctxt->doc_buff );
1810 }
1811 else
1812#endif
1813 {
1814 xmlOutputBufferClose( ctxt->doc_buff );
1815 }
1816 }
1817
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001818 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001819 return;
1820}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001821#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001822
1823
Owen Taylor3473f882001-02-23 17:55:21 +00001824/**
1825 * xmlIOHTTPMatch:
1826 * @filename: the URI for matching
1827 *
1828 * check if the URI matches an HTTP one
1829 *
1830 * Returns 1 if matches, 0 otherwise
1831 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001832int
Owen Taylor3473f882001-02-23 17:55:21 +00001833xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001834 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001835 return(1);
1836 return(0);
1837}
1838
1839/**
1840 * xmlIOHTTPOpen:
1841 * @filename: the URI for matching
1842 *
1843 * open an HTTP I/O channel
1844 *
1845 * Returns an I/O context or NULL in case of error
1846 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001847void *
Owen Taylor3473f882001-02-23 17:55:21 +00001848xmlIOHTTPOpen (const char *filename) {
1849 return(xmlNanoHTTPOpen(filename, NULL));
1850}
1851
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001852#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001853/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001854 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001855 * @post_uri: The destination URI for the document
1856 * @compression: The compression desired for the document.
1857 *
1858 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1859 * request. Non-static as is called from the output buffer creation routine.
1860 *
1861 * Returns an I/O context or NULL in case of error.
1862 */
1863
1864void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001865xmlIOHTTPOpenW(const char *post_uri, int compression)
1866{
Daniel Veillardf012a642001-07-23 19:10:52 +00001867
Daniel Veillard572577e2002-01-18 16:23:55 +00001868 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001869
Daniel Veillard572577e2002-01-18 16:23:55 +00001870 if (post_uri == NULL)
1871 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001872
Daniel Veillard572577e2002-01-18 16:23:55 +00001873 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1874 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001875 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001876 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001877 }
1878
Daniel Veillard572577e2002-01-18 16:23:55 +00001879 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001880
Daniel Veillard572577e2002-01-18 16:23:55 +00001881 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1882 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001883 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001884 xmlFreeHTTPWriteCtxt(ctxt);
1885 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001886 }
1887
1888 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001889 * ** Since the document length is required for an HTTP post,
1890 * ** need to put the document into a buffer. A memory buffer
1891 * ** is being used to avoid pushing the data to disk and back.
1892 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001893
1894#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001895 if ((compression > 0) && (compression <= 9)) {
1896
1897 ctxt->compression = compression;
1898 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1899 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001900#endif
1901 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001902 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001903
Daniel Veillardda3fee42008-09-01 13:08:57 +00001904 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001905 }
1906
Daniel Veillard572577e2002-01-18 16:23:55 +00001907 if (ctxt->doc_buff == NULL) {
1908 xmlFreeHTTPWriteCtxt(ctxt);
1909 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001910 }
1911
Daniel Veillard572577e2002-01-18 16:23:55 +00001912 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001913}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001914#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001915
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001916#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001917/**
1918 * xmlIOHTTPDfltOpenW
1919 * @post_uri: The destination URI for this document.
1920 *
1921 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1922 * HTTP post command. This function should generally not be used as
1923 * the open callback is short circuited in xmlOutputBufferCreateFile.
1924 *
1925 * Returns a pointer to the new IO context.
1926 */
1927static void *
1928xmlIOHTTPDfltOpenW( const char * post_uri ) {
1929 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1930}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001931#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001932
1933/**
Owen Taylor3473f882001-02-23 17:55:21 +00001934 * xmlIOHTTPRead:
1935 * @context: the I/O context
1936 * @buffer: where to drop data
1937 * @len: number of bytes to write
1938 *
1939 * Read @len bytes to @buffer from the I/O channel.
1940 *
1941 * Returns the number of bytes written
1942 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001943int
Owen Taylor3473f882001-02-23 17:55:21 +00001944xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001945 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001946 return(xmlNanoHTTPRead(context, &buffer[0], len));
1947}
1948
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001949#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001950/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001951 * xmlIOHTTPWrite
1952 * @context: previously opened writing context
1953 * @buffer: data to output to temporary buffer
1954 * @len: bytes to output
1955 *
1956 * Collect data from memory buffer into a temporary file for later
1957 * processing.
1958 *
1959 * Returns number of bytes written.
1960 */
1961
1962static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001963xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001964
1965 xmlIOHTTPWriteCtxtPtr ctxt = context;
1966
1967 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1968 return ( -1 );
1969
1970 if ( len > 0 ) {
1971
1972 /* Use gzwrite or fwrite as previously setup in the open call */
1973
1974#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001975 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001976 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1977
1978 else
1979#endif
1980 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1981
1982 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001983 xmlChar msg[500];
1984 xmlStrPrintf(msg, 500,
1985 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001986 "Error appending to internal buffer.",
1987 "Error sending document to URI",
1988 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001989 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001990 }
1991 }
1992
1993 return ( len );
1994}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001995#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001996
1997
1998/**
Owen Taylor3473f882001-02-23 17:55:21 +00001999 * xmlIOHTTPClose:
2000 * @context: the I/O context
2001 *
2002 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002003 *
2004 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002005 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002006int
Owen Taylor3473f882001-02-23 17:55:21 +00002007xmlIOHTTPClose (void * context) {
2008 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00002009 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002010}
Daniel Veillardf012a642001-07-23 19:10:52 +00002011
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002012#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002013/**
2014 * xmlIOHTTCloseWrite
2015 * @context: The I/O context
2016 * @http_mthd: The HTTP method to be used when sending the data
2017 *
2018 * Close the transmit HTTP I/O channel and actually send the data.
2019 */
2020static int
2021xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2022
2023 int close_rc = -1;
2024 int http_rtn = 0;
2025 int content_lgth = 0;
2026 xmlIOHTTPWriteCtxtPtr ctxt = context;
2027
2028 char * http_content = NULL;
2029 char * content_encoding = NULL;
2030 char * content_type = (char *) "text/xml";
2031 void * http_ctxt = NULL;
2032
2033 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2034 return ( -1 );
2035
2036 /* Retrieve the content from the appropriate buffer */
2037
2038#ifdef HAVE_ZLIB_H
2039
2040 if ( ctxt->compression > 0 ) {
2041 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2042 content_encoding = (char *) "Content-Encoding: gzip";
2043 }
2044 else
2045#endif
2046 {
2047 /* Pull the data out of the memory output buffer */
2048
2049 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002050 http_content = (char *) xmlBufContent(dctxt->buffer);
2051 content_lgth = xmlBufUse(dctxt->buffer);
Daniel Veillardf012a642001-07-23 19:10:52 +00002052 }
2053
2054 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002055 xmlChar msg[500];
2056 xmlStrPrintf(msg, 500,
2057 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2058 "Error retrieving content.\nUnable to",
2059 http_mthd, "data to URI", ctxt->uri );
2060 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002061 }
2062
2063 else {
2064
2065 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002066 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00002067 content_lgth );
2068
2069 if ( http_ctxt != NULL ) {
2070#ifdef DEBUG_HTTP
2071 /* If testing/debugging - dump reply with request content */
2072
2073 FILE * tst_file = NULL;
2074 char buffer[ 4096 ];
2075 char * dump_name = NULL;
2076 int avail;
2077
2078 xmlGenericError( xmlGenericErrorContext,
2079 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2080 http_mthd, ctxt->uri,
2081 xmlNanoHTTPReturnCode( http_ctxt ) );
2082
2083 /*
2084 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002085 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002086 ** standard error context.
2087 */
2088
2089 dump_name = tempnam( NULL, "lxml" );
2090 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002091 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002092
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002093 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002094 if ( tst_file != NULL ) {
2095 xmlGenericError( xmlGenericErrorContext,
2096 "Transmitted content saved in file: %s\n", buffer );
2097
2098 fwrite( http_content, sizeof( char ),
2099 content_lgth, tst_file );
2100 fclose( tst_file );
2101 }
2102
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002103 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002104 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002105 if ( tst_file != NULL ) {
2106 xmlGenericError( xmlGenericErrorContext,
2107 "Reply content saved in file: %s\n", buffer );
2108
2109
2110 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2111 buffer, sizeof( buffer ) )) > 0 ) {
2112
2113 fwrite( buffer, sizeof( char ), avail, tst_file );
2114 }
2115
2116 fclose( tst_file );
2117 }
2118
2119 free( dump_name );
2120 }
2121#endif /* DEBUG_HTTP */
2122
2123 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2124 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2125 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002126 else {
2127 xmlChar msg[500];
2128 xmlStrPrintf(msg, 500,
2129 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002130 http_mthd, content_lgth,
2131 "bytes to URI", ctxt->uri,
2132 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002133 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2134 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002135
2136 xmlNanoHTTPClose( http_ctxt );
2137 xmlFree( content_type );
2138 }
2139 }
2140
2141 /* Final cleanups */
2142
2143 xmlFreeHTTPWriteCtxt( ctxt );
2144
2145 return ( close_rc );
2146}
2147
2148/**
2149 * xmlIOHTTPClosePut
2150 *
2151 * @context: The I/O context
2152 *
2153 * Close the transmit HTTP I/O channel and actually send data using a PUT
2154 * HTTP method.
2155 */
2156static int
2157xmlIOHTTPClosePut( void * ctxt ) {
2158 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2159}
2160
2161
2162/**
2163 * xmlIOHTTPClosePost
2164 *
2165 * @context: The I/O context
2166 *
2167 * Close the transmit HTTP I/O channel and actually send data using a POST
2168 * HTTP method.
2169 */
2170static int
2171xmlIOHTTPClosePost( void * ctxt ) {
2172 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2173}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002174#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002175
Owen Taylor3473f882001-02-23 17:55:21 +00002176#endif /* LIBXML_HTTP_ENABLED */
2177
2178#ifdef LIBXML_FTP_ENABLED
2179/************************************************************************
2180 * *
2181 * I/O for FTP file accesses *
2182 * *
2183 ************************************************************************/
2184/**
2185 * xmlIOFTPMatch:
2186 * @filename: the URI for matching
2187 *
2188 * check if the URI matches an FTP one
2189 *
2190 * Returns 1 if matches, 0 otherwise
2191 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002192int
Owen Taylor3473f882001-02-23 17:55:21 +00002193xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002194 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002195 return(1);
2196 return(0);
2197}
2198
2199/**
2200 * xmlIOFTPOpen:
2201 * @filename: the URI for matching
2202 *
2203 * open an FTP I/O channel
2204 *
2205 * Returns an I/O context or NULL in case of error
2206 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002207void *
Owen Taylor3473f882001-02-23 17:55:21 +00002208xmlIOFTPOpen (const char *filename) {
2209 return(xmlNanoFTPOpen(filename));
2210}
2211
2212/**
2213 * xmlIOFTPRead:
2214 * @context: the I/O context
2215 * @buffer: where to drop data
2216 * @len: number of bytes to write
2217 *
2218 * Read @len bytes to @buffer from the I/O channel.
2219 *
2220 * Returns the number of bytes written
2221 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002222int
Owen Taylor3473f882001-02-23 17:55:21 +00002223xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002224 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002225 return(xmlNanoFTPRead(context, &buffer[0], len));
2226}
2227
2228/**
2229 * xmlIOFTPClose:
2230 * @context: the I/O context
2231 *
2232 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002233 *
2234 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002235 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002236int
Owen Taylor3473f882001-02-23 17:55:21 +00002237xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002238 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002239}
2240#endif /* LIBXML_FTP_ENABLED */
2241
2242
2243/**
2244 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002245 * @matchFunc: the xmlInputMatchCallback
2246 * @openFunc: the xmlInputOpenCallback
2247 * @readFunc: the xmlInputReadCallback
2248 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002249 *
2250 * Register a new set of I/O callback for handling parser input.
2251 *
2252 * Returns the registered handler number or -1 in case of error
2253 */
2254int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002255xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2256 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2257 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002258 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2259 return(-1);
2260 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002261 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2262 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2263 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2264 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002265 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002266 return(xmlInputCallbackNr++);
2267}
2268
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002269#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002270/**
2271 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002272 * @matchFunc: the xmlOutputMatchCallback
2273 * @openFunc: the xmlOutputOpenCallback
2274 * @writeFunc: the xmlOutputWriteCallback
2275 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002276 *
2277 * Register a new set of I/O callback for handling output.
2278 *
2279 * Returns the registered handler number or -1 in case of error
2280 */
2281int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002282xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2283 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2284 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002285 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002286 return(-1);
2287 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002288 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2289 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2290 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2291 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002292 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002293 return(xmlOutputCallbackNr++);
2294}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002295#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002296
2297/**
2298 * xmlRegisterDefaultInputCallbacks:
2299 *
2300 * Registers the default compiled-in I/O handlers.
2301 */
2302void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002303xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002304 if (xmlInputCallbackInitialized)
2305 return;
2306
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002307#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2308 xmlInitPlatformSpecificIo();
2309#endif
2310
Owen Taylor3473f882001-02-23 17:55:21 +00002311 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2312 xmlFileRead, xmlFileClose);
2313#ifdef HAVE_ZLIB_H
2314 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2315 xmlGzfileRead, xmlGzfileClose);
2316#endif /* HAVE_ZLIB_H */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002317#ifdef HAVE_LZMA_H
2318 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2319 xmlXzfileRead, xmlXzfileClose);
2320#endif /* HAVE_ZLIB_H */
Owen Taylor3473f882001-02-23 17:55:21 +00002321
2322#ifdef LIBXML_HTTP_ENABLED
2323 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2324 xmlIOHTTPRead, xmlIOHTTPClose);
2325#endif /* LIBXML_HTTP_ENABLED */
2326
2327#ifdef LIBXML_FTP_ENABLED
2328 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2329 xmlIOFTPRead, xmlIOFTPClose);
2330#endif /* LIBXML_FTP_ENABLED */
2331 xmlInputCallbackInitialized = 1;
2332}
2333
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002334#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002335/**
2336 * xmlRegisterDefaultOutputCallbacks:
2337 *
2338 * Registers the default compiled-in I/O handlers.
2339 */
2340void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002341xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002342 if (xmlOutputCallbackInitialized)
2343 return;
2344
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002345#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2346 xmlInitPlatformSpecificIo();
2347#endif
2348
Owen Taylor3473f882001-02-23 17:55:21 +00002349 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2350 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002351
2352#ifdef LIBXML_HTTP_ENABLED
2353 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2354 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2355#endif
2356
Owen Taylor3473f882001-02-23 17:55:21 +00002357/*********************************
2358 No way a-priori to distinguish between gzipped files from
2359 uncompressed ones except opening if existing then closing
2360 and saving with same compression ratio ... a pain.
2361
2362#ifdef HAVE_ZLIB_H
2363 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2364 xmlGzfileWrite, xmlGzfileClose);
2365#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002366
2367 Nor FTP PUT ....
2368#ifdef LIBXML_FTP_ENABLED
2369 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2370 xmlIOFTPWrite, xmlIOFTPClose);
2371#endif
2372 **********************************/
2373 xmlOutputCallbackInitialized = 1;
2374}
2375
Daniel Veillardf012a642001-07-23 19:10:52 +00002376#ifdef LIBXML_HTTP_ENABLED
2377/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002378 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002379 *
2380 * By default, libxml submits HTTP output requests using the "PUT" method.
2381 * Calling this method changes the HTTP output method to use the "POST"
2382 * method instead.
2383 *
2384 */
2385void
2386xmlRegisterHTTPPostCallbacks( void ) {
2387
2388 /* Register defaults if not done previously */
2389
2390 if ( xmlOutputCallbackInitialized == 0 )
2391 xmlRegisterDefaultOutputCallbacks( );
2392
2393 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2394 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2395 return;
2396}
2397#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002398#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002399
Owen Taylor3473f882001-02-23 17:55:21 +00002400/**
2401 * xmlAllocParserInputBuffer:
2402 * @enc: the charset encoding if known
2403 *
2404 * Create a buffered parser input for progressive parsing
2405 *
2406 * Returns the new parser input or NULL
2407 */
2408xmlParserInputBufferPtr
2409xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2410 xmlParserInputBufferPtr ret;
2411
2412 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2413 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002414 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002415 return(NULL);
2416 }
2417 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002418 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002419 if (ret->buffer == NULL) {
2420 xmlFree(ret);
2421 return(NULL);
2422 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002423 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Owen Taylor3473f882001-02-23 17:55:21 +00002424 ret->encoder = xmlGetCharEncodingHandler(enc);
2425 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002426 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002427 else
2428 ret->raw = NULL;
2429 ret->readcallback = NULL;
2430 ret->closecallback = NULL;
2431 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002432 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002433 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002434
2435 return(ret);
2436}
2437
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002438#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002439/**
2440 * xmlAllocOutputBuffer:
2441 * @encoder: the encoding converter or NULL
2442 *
2443 * Create a buffered parser output
2444 *
2445 * Returns the new parser output or NULL
2446 */
2447xmlOutputBufferPtr
2448xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2449 xmlOutputBufferPtr ret;
2450
2451 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2452 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002453 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002454 return(NULL);
2455 }
2456 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002457 ret->buffer = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00002458 if (ret->buffer == NULL) {
2459 xmlFree(ret);
2460 return(NULL);
2461 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002462
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002463 /* try to avoid a performance problem with Windows realloc() */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002464 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2465 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002466
Daniel Veillardda3fee42008-09-01 13:08:57 +00002467 ret->encoder = encoder;
2468 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002469 ret->conv = xmlBufCreateSize(4000);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002470 if (ret->conv == NULL) {
2471 xmlFree(ret);
2472 return(NULL);
2473 }
2474
2475 /*
2476 * This call is designed to initiate the encoder state
2477 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002478 xmlCharEncOutput(ret, 1);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002479 } else
2480 ret->conv = NULL;
2481 ret->writecallback = NULL;
2482 ret->closecallback = NULL;
2483 ret->context = NULL;
2484 ret->written = 0;
2485
2486 return(ret);
2487}
2488
2489/**
2490 * xmlAllocOutputBufferInternal:
2491 * @encoder: the encoding converter or NULL
2492 *
2493 * Create a buffered parser output
2494 *
2495 * Returns the new parser output or NULL
2496 */
2497xmlOutputBufferPtr
2498xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2499 xmlOutputBufferPtr ret;
2500
2501 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2502 if (ret == NULL) {
2503 xmlIOErrMemory("creating output buffer");
2504 return(NULL);
2505 }
2506 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002507 ret->buffer = xmlBufCreate();
Daniel Veillardda3fee42008-09-01 13:08:57 +00002508 if (ret->buffer == NULL) {
2509 xmlFree(ret);
2510 return(NULL);
2511 }
2512
2513
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002514 /*
2515 * For conversion buffers we use the special IO handling
2516 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002517 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002518
Owen Taylor3473f882001-02-23 17:55:21 +00002519 ret->encoder = encoder;
2520 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002521 ret->conv = xmlBufCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002522 if (ret->conv == NULL) {
2523 xmlFree(ret);
2524 return(NULL);
2525 }
2526
Owen Taylor3473f882001-02-23 17:55:21 +00002527 /*
2528 * This call is designed to initiate the encoder state
2529 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002530 xmlCharEncOutput(ret, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002531 } else
2532 ret->conv = NULL;
2533 ret->writecallback = NULL;
2534 ret->closecallback = NULL;
2535 ret->context = NULL;
2536 ret->written = 0;
2537
2538 return(ret);
2539}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002540
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002541#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002542
2543/**
2544 * xmlFreeParserInputBuffer:
2545 * @in: a buffered parser input
2546 *
2547 * Free up the memory used by a buffered parser input
2548 */
2549void
2550xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002551 if (in == NULL) return;
2552
Owen Taylor3473f882001-02-23 17:55:21 +00002553 if (in->raw) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002554 xmlBufFree(in->raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002555 in->raw = NULL;
2556 }
2557 if (in->encoder != NULL) {
2558 xmlCharEncCloseFunc(in->encoder);
2559 }
2560 if (in->closecallback != NULL) {
2561 in->closecallback(in->context);
2562 }
2563 if (in->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002564 xmlBufFree(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00002565 in->buffer = NULL;
2566 }
2567
Owen Taylor3473f882001-02-23 17:55:21 +00002568 xmlFree(in);
2569}
2570
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002571#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002572/**
2573 * xmlOutputBufferClose:
2574 * @out: a buffered output
2575 *
2576 * flushes and close the output I/O channel
2577 * and free up all the associated resources
2578 *
2579 * Returns the number of byte written or -1 in case of error.
2580 */
2581int
Daniel Veillard828ce832003-10-08 19:19:10 +00002582xmlOutputBufferClose(xmlOutputBufferPtr out)
2583{
Owen Taylor3473f882001-02-23 17:55:21 +00002584 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002585 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002586
2587 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002588 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002589 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002590 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002591 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002592 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002593 }
2594 written = out->written;
2595 if (out->conv) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002596 xmlBufFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002597 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002598 }
2599 if (out->encoder != NULL) {
2600 xmlCharEncCloseFunc(out->encoder);
2601 }
2602 if (out->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002603 xmlBufFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002604 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002605 }
2606
Daniel Veillard828ce832003-10-08 19:19:10 +00002607 if (out->error)
2608 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002609 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002610 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002611}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002612#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002613
Daniel Veillard1b243b42004-06-08 10:16:42 +00002614xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002615__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002616 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002617 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002618 void *context = NULL;
2619
2620 if (xmlInputCallbackInitialized == 0)
2621 xmlRegisterDefaultInputCallbacks();
2622
2623 if (URI == NULL) return(NULL);
2624
2625 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002626 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002627 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002628 */
2629 if (context == NULL) {
2630 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2631 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2632 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002633 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002634 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002635 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002636 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002637 }
Owen Taylor3473f882001-02-23 17:55:21 +00002638 }
2639 }
2640 if (context == NULL) {
2641 return(NULL);
2642 }
2643
2644 /*
2645 * Allocate the Input buffer front-end.
2646 */
2647 ret = xmlAllocParserInputBuffer(enc);
2648 if (ret != NULL) {
2649 ret->context = context;
2650 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2651 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002652#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002653 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2654 (strcmp(URI, "-") != 0)) {
Mark Adlera7e79f22010-01-19 16:28:48 +01002655#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2656 ret->compressed = !gzdirect(context);
2657#else
William M. Brackc07329e2003-09-08 01:57:30 +00002658 if (((z_stream *)context)->avail_in > 4) {
2659 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002660 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002661 if (gzread(context, buff4, 4) == 4) {
2662 if (strncmp(buff4, cptr, 4) == 0)
2663 ret->compressed = 0;
2664 else
2665 ret->compressed = 1;
2666 gzrewind(context);
2667 }
2668 }
Mark Adlera7e79f22010-01-19 16:28:48 +01002669#endif
William M. Brackc07329e2003-09-08 01:57:30 +00002670 }
2671#endif
Daniel Veillard63588f42013-05-10 14:01:46 +08002672#ifdef HAVE_LZMA_H
2673 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2674 (strcmp(URI, "-") != 0)) {
2675 ret->compressed = __libxml2_xzcompressed(context);
2676 }
2677#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002678 }
William M. Brack42331a92004-07-29 07:07:16 +00002679 else
2680 xmlInputCallbackTable[i].closecallback (context);
2681
Owen Taylor3473f882001-02-23 17:55:21 +00002682 return(ret);
2683}
2684
2685/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002686 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002687 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002688 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002689 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002690 * Create a buffered parser input for the progressive parsing of a file
2691 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002692 * Automatic support for ZLIB/Compress compressed document is provided
2693 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002694 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002695 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002696 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002697 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002698xmlParserInputBufferPtr
2699xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2700 if ((xmlParserInputBufferCreateFilenameValue)) {
2701 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2702 }
2703 return __xmlParserInputBufferCreateFilename(URI, enc);
2704}
2705
2706#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002707xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002708__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002709 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002710 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002711 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002712 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002713 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002714 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002715 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002716#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002717 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002718#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002719
Owen Taylor3473f882001-02-23 17:55:21 +00002720 if (xmlOutputCallbackInitialized == 0)
2721 xmlRegisterDefaultOutputCallbacks();
2722
2723 if (URI == NULL) return(NULL);
2724
Daniel Veillard966a31e2004-05-09 02:58:44 +00002725 puri = xmlParseURI(URI);
2726 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002727#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002728 if ((puri->scheme != NULL) &&
2729 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002730 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002731#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002732 /*
2733 * try to limit the damages of the URI unescaping code.
2734 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002735 if ((puri->scheme == NULL) ||
2736 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002737 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2738 xmlFreeURI(puri);
2739 }
Owen Taylor3473f882001-02-23 17:55:21 +00002740
2741 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002742 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002743 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002744 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002745 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002746 if (unescaped != NULL) {
2747#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002748 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002749 context = xmlGzfileOpenW(unescaped, compression);
2750 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002751 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002752 if (ret != NULL) {
2753 ret->context = context;
2754 ret->writecallback = xmlGzfileWrite;
2755 ret->closecallback = xmlGzfileClose;
2756 }
2757 xmlFree(unescaped);
2758 return(ret);
2759 }
2760 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002761#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002762 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2763 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2764 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2765#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2766 /* Need to pass compression parameter into HTTP open calls */
2767 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2768 context = xmlIOHTTPOpenW(unescaped, compression);
2769 else
2770#endif
2771 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2772 if (context != NULL)
2773 break;
2774 }
2775 }
2776 xmlFree(unescaped);
2777 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002778
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002779 /*
2780 * If this failed try with a non-escaped URI this may be a strange
2781 * filename
2782 */
2783 if (context == NULL) {
2784#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002785 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002786 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002787 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002788 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002789 if (ret != NULL) {
2790 ret->context = context;
2791 ret->writecallback = xmlGzfileWrite;
2792 ret->closecallback = xmlGzfileClose;
2793 }
2794 return(ret);
2795 }
2796 }
2797#endif
2798 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2799 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002800 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002801#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2802 /* Need to pass compression parameter into HTTP open calls */
2803 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2804 context = xmlIOHTTPOpenW(URI, compression);
2805 else
2806#endif
2807 context = xmlOutputCallbackTable[i].opencallback(URI);
2808 if (context != NULL)
2809 break;
2810 }
Owen Taylor3473f882001-02-23 17:55:21 +00002811 }
2812 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002813
Owen Taylor3473f882001-02-23 17:55:21 +00002814 if (context == NULL) {
2815 return(NULL);
2816 }
2817
2818 /*
2819 * Allocate the Output buffer front-end.
2820 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002821 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002822 if (ret != NULL) {
2823 ret->context = context;
2824 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2825 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2826 }
2827 return(ret);
2828}
Daniel Veillard0335a842004-06-02 16:18:40 +00002829
2830/**
2831 * xmlOutputBufferCreateFilename:
2832 * @URI: a C string containing the URI or filename
2833 * @encoder: the encoding converter or NULL
2834 * @compression: the compression ration (0 none, 9 max).
2835 *
2836 * Create a buffered output for the progressive saving of a file
2837 * If filename is "-' then we use stdout as the output.
2838 * Automatic support for ZLIB/Compress compressed document is provided
2839 * by default if found at compile-time.
2840 * TODO: currently if compression is set, the library only support
2841 * writing to a local file.
2842 *
2843 * Returns the new output or NULL
2844 */
2845xmlOutputBufferPtr
2846xmlOutputBufferCreateFilename(const char *URI,
2847 xmlCharEncodingHandlerPtr encoder,
2848 int compression ATTRIBUTE_UNUSED) {
2849 if ((xmlOutputBufferCreateFilenameValue)) {
2850 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2851 }
2852 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2853}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002854#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002855
2856/**
2857 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002858 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002859 * @enc: the charset encoding if known
2860 *
2861 * Create a buffered parser input for the progressive parsing of a FILE *
2862 * buffered C I/O
2863 *
2864 * Returns the new parser input or NULL
2865 */
2866xmlParserInputBufferPtr
2867xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2868 xmlParserInputBufferPtr ret;
2869
2870 if (xmlInputCallbackInitialized == 0)
2871 xmlRegisterDefaultInputCallbacks();
2872
2873 if (file == NULL) return(NULL);
2874
2875 ret = xmlAllocParserInputBuffer(enc);
2876 if (ret != NULL) {
2877 ret->context = file;
2878 ret->readcallback = xmlFileRead;
2879 ret->closecallback = xmlFileFlush;
2880 }
2881
2882 return(ret);
2883}
2884
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002885#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002886/**
2887 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002888 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002889 * @encoder: the encoding converter or NULL
2890 *
2891 * Create a buffered output for the progressive saving to a FILE *
2892 * buffered C I/O
2893 *
2894 * Returns the new parser output or NULL
2895 */
2896xmlOutputBufferPtr
2897xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2898 xmlOutputBufferPtr ret;
2899
2900 if (xmlOutputCallbackInitialized == 0)
2901 xmlRegisterDefaultOutputCallbacks();
2902
2903 if (file == NULL) return(NULL);
2904
Daniel Veillardda3fee42008-09-01 13:08:57 +00002905 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002906 if (ret != NULL) {
2907 ret->context = file;
2908 ret->writecallback = xmlFileWrite;
2909 ret->closecallback = xmlFileFlush;
2910 }
2911
2912 return(ret);
2913}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002914
2915/**
2916 * xmlOutputBufferCreateBuffer:
2917 * @buffer: a xmlBufferPtr
2918 * @encoder: the encoding converter or NULL
2919 *
2920 * Create a buffered output for the progressive saving to a xmlBuffer
2921 *
2922 * Returns the new parser output or NULL
2923 */
2924xmlOutputBufferPtr
2925xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2926 xmlCharEncodingHandlerPtr encoder) {
2927 xmlOutputBufferPtr ret;
2928
2929 if (buffer == NULL) return(NULL);
2930
Rob Richardsa44f2342005-11-09 18:03:45 +00002931 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2932 xmlBufferWrite,
2933 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002934 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002935
2936 return(ret);
2937}
2938
Daniel Veillarde258ade2012-08-06 11:16:30 +08002939/**
2940 * xmlOutputBufferGetContent:
2941 * @out: an xmlOutputBufferPtr
2942 *
2943 * Gives a pointer to the data currently held in the output buffer
2944 *
2945 * Returns a pointer to the data or NULL in case of error
2946 */
2947const xmlChar *
2948xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2949 if ((out == NULL) || (out->buffer == NULL))
2950 return(NULL);
2951
2952 return(xmlBufContent(out->buffer));
2953}
2954
2955/**
2956 * xmlOutputBufferGetSize:
2957 * @out: an xmlOutputBufferPtr
2958 *
2959 * Gives the length of the data currently held in the output buffer
2960 *
2961 * Returns 0 in case or error or no data is held, the size otherwise
2962 */
2963size_t
2964xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2965 if ((out == NULL) || (out->buffer == NULL))
2966 return(0);
2967
2968 return(xmlBufUse(out->buffer));
2969}
2970
2971
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002972#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002973
2974/**
2975 * xmlParserInputBufferCreateFd:
2976 * @fd: a file descriptor number
2977 * @enc: the charset encoding if known
2978 *
2979 * Create a buffered parser input for the progressive parsing for the input
2980 * from a file descriptor
2981 *
2982 * Returns the new parser input or NULL
2983 */
2984xmlParserInputBufferPtr
2985xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2986 xmlParserInputBufferPtr ret;
2987
2988 if (fd < 0) return(NULL);
2989
2990 ret = xmlAllocParserInputBuffer(enc);
2991 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002992 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002993 ret->readcallback = xmlFdRead;
2994 ret->closecallback = xmlFdClose;
2995 }
2996
2997 return(ret);
2998}
2999
3000/**
3001 * xmlParserInputBufferCreateMem:
3002 * @mem: the memory input
3003 * @size: the length of the memory block
3004 * @enc: the charset encoding if known
3005 *
3006 * Create a buffered parser input for the progressive parsing for the input
3007 * from a memory area.
3008 *
3009 * Returns the new parser input or NULL
3010 */
3011xmlParserInputBufferPtr
3012xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
3013 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00003014 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00003015
3016 if (size <= 0) return(NULL);
3017 if (mem == NULL) return(NULL);
3018
3019 ret = xmlAllocParserInputBuffer(enc);
3020 if (ret != NULL) {
3021 ret->context = (void *) mem;
3022 ret->readcallback = (xmlInputReadCallback) xmlNop;
3023 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003024 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00003025 if (errcode != 0) {
3026 xmlFree(ret);
3027 return(NULL);
3028 }
Owen Taylor3473f882001-02-23 17:55:21 +00003029 }
3030
3031 return(ret);
3032}
3033
3034/**
Daniel Veillard53350552003-09-18 13:35:51 +00003035 * xmlParserInputBufferCreateStatic:
3036 * @mem: the memory input
3037 * @size: the length of the memory block
3038 * @enc: the charset encoding if known
3039 *
3040 * Create a buffered parser input for the progressive parsing for the input
3041 * from an immutable memory area. This will not copy the memory area to
3042 * the buffer, but the memory is expected to be available until the end of
3043 * the parsing, this is useful for example when using mmap'ed file.
3044 *
3045 * Returns the new parser input or NULL
3046 */
3047xmlParserInputBufferPtr
3048xmlParserInputBufferCreateStatic(const char *mem, int size,
3049 xmlCharEncoding enc) {
3050 xmlParserInputBufferPtr ret;
3051
3052 if (size <= 0) return(NULL);
3053 if (mem == NULL) return(NULL);
3054
3055 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3056 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003057 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003058 return(NULL);
3059 }
3060 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003061 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003062 if (ret->buffer == NULL) {
3063 xmlFree(ret);
3064 return(NULL);
3065 }
3066 ret->encoder = xmlGetCharEncodingHandler(enc);
3067 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003068 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00003069 else
3070 ret->raw = NULL;
3071 ret->compressed = -1;
3072 ret->context = (void *) mem;
3073 ret->readcallback = NULL;
3074 ret->closecallback = NULL;
3075
3076 return(ret);
3077}
3078
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003079#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003080/**
Owen Taylor3473f882001-02-23 17:55:21 +00003081 * xmlOutputBufferCreateFd:
3082 * @fd: a file descriptor number
3083 * @encoder: the encoding converter or NULL
3084 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003085 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003086 * to a file descriptor
3087 *
3088 * Returns the new parser output or NULL
3089 */
3090xmlOutputBufferPtr
3091xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3092 xmlOutputBufferPtr ret;
3093
3094 if (fd < 0) return(NULL);
3095
Daniel Veillardda3fee42008-09-01 13:08:57 +00003096 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003097 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003098 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003099 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003100 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003101 }
3102
3103 return(ret);
3104}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003105#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003106
3107/**
3108 * xmlParserInputBufferCreateIO:
3109 * @ioread: an I/O read function
3110 * @ioclose: an I/O close function
3111 * @ioctx: an I/O handler
3112 * @enc: the charset encoding if known
3113 *
3114 * Create a buffered parser input for the progressive parsing for the input
3115 * from an I/O handler
3116 *
3117 * Returns the new parser input or NULL
3118 */
3119xmlParserInputBufferPtr
3120xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3121 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3122 xmlParserInputBufferPtr ret;
3123
3124 if (ioread == NULL) return(NULL);
3125
3126 ret = xmlAllocParserInputBuffer(enc);
3127 if (ret != NULL) {
3128 ret->context = (void *) ioctx;
3129 ret->readcallback = ioread;
3130 ret->closecallback = ioclose;
3131 }
3132
3133 return(ret);
3134}
3135
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003136#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003137/**
3138 * xmlOutputBufferCreateIO:
3139 * @iowrite: an I/O write function
3140 * @ioclose: an I/O close function
3141 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003142 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003143 *
3144 * Create a buffered output for the progressive saving
3145 * to an I/O handler
3146 *
3147 * Returns the new parser output or NULL
3148 */
3149xmlOutputBufferPtr
3150xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3151 xmlOutputCloseCallback ioclose, void *ioctx,
3152 xmlCharEncodingHandlerPtr encoder) {
3153 xmlOutputBufferPtr ret;
3154
3155 if (iowrite == NULL) return(NULL);
3156
Daniel Veillardda3fee42008-09-01 13:08:57 +00003157 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003158 if (ret != NULL) {
3159 ret->context = (void *) ioctx;
3160 ret->writecallback = iowrite;
3161 ret->closecallback = ioclose;
3162 }
3163
3164 return(ret);
3165}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003166#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003167
3168/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003169 * xmlParserInputBufferCreateFilenameDefault:
3170 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3171 *
3172 * Registers a callback for URI input file handling
3173 *
3174 * Returns the old value of the registration function
3175 */
3176xmlParserInputBufferCreateFilenameFunc
3177xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3178{
3179 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3180 if (old == NULL) {
3181 old = __xmlParserInputBufferCreateFilename;
3182 }
3183
3184 xmlParserInputBufferCreateFilenameValue = func;
3185 return(old);
3186}
3187
3188/**
3189 * xmlOutputBufferCreateFilenameDefault:
3190 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3191 *
3192 * Registers a callback for URI output file handling
3193 *
3194 * Returns the old value of the registration function
3195 */
3196xmlOutputBufferCreateFilenameFunc
3197xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3198{
3199 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3200#ifdef LIBXML_OUTPUT_ENABLED
3201 if (old == NULL) {
3202 old = __xmlOutputBufferCreateFilename;
3203 }
3204#endif
3205 xmlOutputBufferCreateFilenameValue = func;
3206 return(old);
3207}
3208
3209/**
Owen Taylor3473f882001-02-23 17:55:21 +00003210 * xmlParserInputBufferPush:
3211 * @in: a buffered parser input
3212 * @len: the size in bytes of the array.
3213 * @buf: an char array
3214 *
3215 * Push the content of the arry in the input buffer
3216 * This routine handle the I18N transcoding to internal UTF-8
3217 * This is used when operating the parser in progressive (push) mode.
3218 *
3219 * Returns the number of chars read and stored in the buffer, or -1
3220 * in case of error.
3221 */
3222int
3223xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3224 int len, const char *buf) {
3225 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003226 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003227
3228 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003229 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003230 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003231 unsigned int use;
3232
Owen Taylor3473f882001-02-23 17:55:21 +00003233 /*
3234 * Store the data in the incoming raw buffer
3235 */
3236 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003237 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003238 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003239 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003240 if (ret != 0)
3241 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003242
3243 /*
3244 * convert as much as possible to the parser reading buffer.
3245 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003246 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003247 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003248 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003249 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003250 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003251 return(-1);
3252 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003253 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003254 } else {
3255 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003256 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003257 if (ret != 0)
3258 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003259 }
3260#ifdef DEBUG_INPUT
3261 xmlGenericError(xmlGenericErrorContext,
3262 "I/O: pushed %d chars, buffer %d/%d\n",
Roumen Petrov89b6f732012-08-04 05:09:56 +03003263 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003264#endif
3265 return(nbchars);
3266}
3267
3268/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003269 * endOfInput:
3270 *
3271 * When reading from an Input channel indicated end of file or error
3272 * don't reread from it again.
3273 */
3274static int
3275endOfInput (void * context ATTRIBUTE_UNUSED,
3276 char * buffer ATTRIBUTE_UNUSED,
3277 int len ATTRIBUTE_UNUSED) {
3278 return(0);
3279}
3280
3281/**
Owen Taylor3473f882001-02-23 17:55:21 +00003282 * xmlParserInputBufferGrow:
3283 * @in: a buffered parser input
3284 * @len: indicative value of the amount of chars to read
3285 *
3286 * Grow up the content of the input buffer, the old data are preserved
3287 * This routine handle the I18N transcoding to internal UTF-8
3288 * This routine is used when operating the parser in normal (pull) mode
3289 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003290 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003291 * onto in->buffer or in->raw
3292 *
3293 * Returns the number of chars read and stored in the buffer, or -1
3294 * in case of error.
3295 */
3296int
3297xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3298 char *buffer = NULL;
3299 int res = 0;
3300 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003301
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003302 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003303 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003304 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003305
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003306 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003307 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003308 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003309 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003310 }
Owen Taylor3473f882001-02-23 17:55:21 +00003311
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003312 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3313 xmlIOErrMemory("growing input buffer");
3314 in->error = XML_ERR_NO_MEMORY;
3315 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003316 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003317 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003318
3319 /*
3320 * Call the read method for this I/O type.
3321 */
3322 if (in->readcallback != NULL) {
3323 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003324 if (res <= 0)
3325 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003326 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003327 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003328 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003329 return(-1);
3330 }
3331 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003332 return(-1);
3333 }
Daniel Veillard63588f42013-05-10 14:01:46 +08003334
3335 /*
3336 * try to establish compressed status of input if not done already
3337 */
3338 if (in->compressed == -1) {
3339#ifdef HAVE_LZMA_H
3340 if (in->readcallback == xmlXzfileRead)
3341 in->compressed = __libxml2_xzcompressed(in->context);
3342#endif
3343 }
3344
Owen Taylor3473f882001-02-23 17:55:21 +00003345 len = res;
3346 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003347 unsigned int use;
3348
Owen Taylor3473f882001-02-23 17:55:21 +00003349 /*
3350 * Store the data in the incoming raw buffer
3351 */
3352 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003353 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003354 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003355 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003356 if (res != 0)
3357 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003358
3359 /*
3360 * convert as much as possible to the parser reading buffer.
3361 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003362 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003363 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003364 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003365 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003366 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003367 return(-1);
3368 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003369 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003370 } else {
3371 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003372 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003373 }
3374#ifdef DEBUG_INPUT
3375 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003376 "I/O: read %d chars, buffer %d\n",
3377 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003378#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003379 return(nbchars);
3380}
3381
3382/**
3383 * xmlParserInputBufferRead:
3384 * @in: a buffered parser input
3385 * @len: indicative value of the amount of chars to read
3386 *
3387 * Refresh the content of the input buffer, the old data are considered
3388 * consumed
3389 * This routine handle the I18N transcoding to internal UTF-8
3390 *
3391 * Returns the number of chars read and stored in the buffer, or -1
3392 * in case of error.
3393 */
3394int
3395xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003396 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003397 if (in->readcallback != NULL)
3398 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003399 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003400 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003401 else
3402 return(-1);
3403}
3404
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003405#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003406/**
3407 * xmlOutputBufferWrite:
3408 * @out: a buffered parser output
3409 * @len: the size in bytes of the array.
3410 * @buf: an char array
3411 *
3412 * Write the content of the array in the output I/O buffer
3413 * This routine handle the I18N transcoding from internal UTF-8
3414 * The buffer is lossless, i.e. will store in case of partial
3415 * or delayed writes.
3416 *
3417 * Returns the number of chars immediately written, or -1
3418 * in case of error.
3419 */
3420int
3421xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3422 int nbchars = 0; /* number of chars to output to I/O */
3423 int ret; /* return from function call */
3424 int written = 0; /* number of char written to I/O so far */
3425 int chunk; /* number of byte curreent processed from buf */
3426
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003427 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003428 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003429 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003430
3431 do {
3432 chunk = len;
3433 if (chunk > 4 * MINLEN)
3434 chunk = 4 * MINLEN;
3435
3436 /*
3437 * first handle encoding stuff.
3438 */
3439 if (out->encoder != NULL) {
3440 /*
3441 * Store the data in the incoming raw buffer
3442 */
3443 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003444 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003445 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003446 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003447 if (ret != 0)
3448 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003449
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003450 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003451 goto done;
3452
3453 /*
3454 * convert as much as possible to the parser reading buffer.
3455 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003456 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003457 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003458 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003459 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003460 return(-1);
3461 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003462 nbchars = xmlBufUse(out->conv);
Owen Taylor3473f882001-02-23 17:55:21 +00003463 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003464 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003465 if (ret != 0)
3466 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003467 nbchars = xmlBufUse(out->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003468 }
3469 buf += chunk;
3470 len -= chunk;
3471
3472 if ((nbchars < MINLEN) && (len <= 0))
3473 goto done;
3474
3475 if (out->writecallback) {
3476 /*
3477 * second write the stuff to the I/O channel
3478 */
3479 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003480 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003481 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003482 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003483 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003484 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003485 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003486 (const char *)xmlBufContent(out->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003487 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003488 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003489 }
3490 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003491 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003492 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003493 return(ret);
3494 }
3495 out->written += ret;
3496 }
3497 written += nbchars;
3498 } while (len > 0);
3499
3500done:
3501#ifdef DEBUG_INPUT
3502 xmlGenericError(xmlGenericErrorContext,
3503 "I/O: wrote %d chars\n", written);
3504#endif
3505 return(written);
3506}
3507
3508/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003509 * xmlEscapeContent:
3510 * @out: a pointer to an array of bytes to store the result
3511 * @outlen: the length of @out
3512 * @in: a pointer to an array of unescaped UTF-8 bytes
3513 * @inlen: the length of @in
3514 *
3515 * Take a block of UTF-8 chars in and escape them.
3516 * Returns 0 if success, or -1 otherwise
3517 * The value of @inlen after return is the number of octets consumed
3518 * if the return value is positive, else unpredictable.
3519 * The value of @outlen after return is the number of octets consumed.
3520 */
3521static int
3522xmlEscapeContent(unsigned char* out, int *outlen,
3523 const xmlChar* in, int *inlen) {
3524 unsigned char* outstart = out;
3525 const unsigned char* base = in;
3526 unsigned char* outend = out + *outlen;
3527 const unsigned char* inend;
3528
3529 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003530
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003531 while ((in < inend) && (out < outend)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003532 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003533 if (outend - out < 4) break;
3534 *out++ = '&';
3535 *out++ = 'l';
3536 *out++ = 't';
3537 *out++ = ';';
3538 } else if (*in == '>') {
3539 if (outend - out < 4) break;
3540 *out++ = '&';
3541 *out++ = 'g';
3542 *out++ = 't';
3543 *out++ = ';';
3544 } else if (*in == '&') {
3545 if (outend - out < 5) break;
3546 *out++ = '&';
3547 *out++ = 'a';
3548 *out++ = 'm';
3549 *out++ = 'p';
3550 *out++ = ';';
3551 } else if (*in == '\r') {
3552 if (outend - out < 5) break;
3553 *out++ = '&';
3554 *out++ = '#';
3555 *out++ = '1';
3556 *out++ = '3';
3557 *out++ = ';';
3558 } else {
3559 *out++ = (unsigned char) *in;
3560 }
3561 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003562 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003563 *outlen = out - outstart;
3564 *inlen = in - base;
3565 return(0);
3566}
3567
3568/**
3569 * xmlOutputBufferWriteEscape:
3570 * @out: a buffered parser output
3571 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003572 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003573 *
3574 * Write the content of the string in the output I/O buffer
3575 * This routine escapes the caracters and then handle the I18N
3576 * transcoding from internal UTF-8
3577 * The buffer is lossless, i.e. will store in case of partial
3578 * or delayed writes.
3579 *
3580 * Returns the number of chars immediately written, or -1
3581 * in case of error.
3582 */
3583int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003584xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3585 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003586 int nbchars = 0; /* number of chars to output to I/O */
3587 int ret; /* return from function call */
3588 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003589 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003590 int chunk; /* number of byte currently processed from str */
3591 int len; /* number of bytes in str */
3592 int cons; /* byte from str consumed */
3593
Daniel Veillardce244ad2004-11-05 10:03:46 +00003594 if ((out == NULL) || (out->error) || (str == NULL) ||
3595 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003596 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3597 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003598 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003599 if (len < 0) return(0);
3600 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003601 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003602
3603 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003604 oldwritten = written;
3605
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003606 /*
3607 * how many bytes to consume and how many bytes to store.
3608 */
3609 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003610 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003611
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003612 /*
3613 * make sure we have enough room to save first, if this is
3614 * not the case force a flush, but make sure we stay in the loop
3615 */
3616 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003617 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003618 return(-1);
3619 oldwritten = -1;
3620 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003621 }
3622
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003623 /*
3624 * first handle encoding stuff.
3625 */
3626 if (out->encoder != NULL) {
3627 /*
3628 * Store the data in the incoming raw buffer
3629 */
3630 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003631 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003632 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003633 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003634 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003635 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003636 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003637 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003638
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003639 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003640 goto done;
3641
3642 /*
3643 * convert as much as possible to the output buffer.
3644 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003645 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003646 if ((ret < 0) && (ret != -3)) {
3647 xmlIOErr(XML_IO_ENCODER, NULL);
3648 out->error = XML_IO_ENCODER;
3649 return(-1);
3650 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003651 nbchars = xmlBufUse(out->conv);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003652 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003653 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003654 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003655 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003656 xmlBufAddLen(out->buffer, chunk);
3657 nbchars = xmlBufUse(out->buffer);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003658 }
3659 str += cons;
3660 len -= cons;
3661
3662 if ((nbchars < MINLEN) && (len <= 0))
3663 goto done;
3664
3665 if (out->writecallback) {
3666 /*
3667 * second write the stuff to the I/O channel
3668 */
3669 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003670 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003671 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003672 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003673 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003674 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003675 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003676 (const char *)xmlBufContent(out->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003677 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003678 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003679 }
3680 if (ret < 0) {
3681 xmlIOErr(XML_IO_WRITE, NULL);
3682 out->error = XML_IO_WRITE;
3683 return(ret);
3684 }
3685 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003686 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3687 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003688 }
3689 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003690 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003691
3692done:
3693#ifdef DEBUG_INPUT
3694 xmlGenericError(xmlGenericErrorContext,
3695 "I/O: wrote %d chars\n", written);
3696#endif
3697 return(written);
3698}
3699
3700/**
Owen Taylor3473f882001-02-23 17:55:21 +00003701 * xmlOutputBufferWriteString:
3702 * @out: a buffered parser output
3703 * @str: a zero terminated C string
3704 *
3705 * Write the content of the string in the output I/O buffer
3706 * This routine handle the I18N transcoding from internal UTF-8
3707 * The buffer is lossless, i.e. will store in case of partial
3708 * or delayed writes.
3709 *
3710 * Returns the number of chars immediately written, or -1
3711 * in case of error.
3712 */
3713int
3714xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3715 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003716
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003717 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003718 if (str == NULL)
3719 return(-1);
3720 len = strlen(str);
3721
3722 if (len > 0)
3723 return(xmlOutputBufferWrite(out, len, str));
3724 return(len);
3725}
3726
3727/**
3728 * xmlOutputBufferFlush:
3729 * @out: a buffered output
3730 *
3731 * flushes the output I/O channel
3732 *
3733 * Returns the number of byte written or -1 in case of error.
3734 */
3735int
3736xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3737 int nbchars = 0, ret = 0;
3738
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003739 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003740 /*
3741 * first handle encoding stuff.
3742 */
3743 if ((out->conv != NULL) && (out->encoder != NULL)) {
3744 /*
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003745 * convert as much as possible to the parser output buffer.
Owen Taylor3473f882001-02-23 17:55:21 +00003746 */
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003747 do {
3748 nbchars = xmlCharEncOutput(out, 0);
3749 if (nbchars < 0) {
3750 xmlIOErr(XML_IO_ENCODER, NULL);
3751 out->error = XML_IO_ENCODER;
3752 return(-1);
3753 }
3754 } while (nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003755 }
3756
3757 /*
3758 * second flush the stuff to the I/O channel
3759 */
3760 if ((out->conv != NULL) && (out->encoder != NULL) &&
3761 (out->writecallback != NULL)) {
3762 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003763 (const char *)xmlBufContent(out->conv),
3764 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003765 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003766 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003767 } else if (out->writecallback != NULL) {
3768 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003769 (const char *)xmlBufContent(out->buffer),
3770 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003771 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003772 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003773 }
3774 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003775 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003776 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003777 return(ret);
3778 }
3779 out->written += ret;
3780
3781#ifdef DEBUG_INPUT
3782 xmlGenericError(xmlGenericErrorContext,
3783 "I/O: flushed %d chars\n", ret);
3784#endif
3785 return(ret);
3786}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003787#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003788
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003789/**
Owen Taylor3473f882001-02-23 17:55:21 +00003790 * xmlParserGetDirectory:
3791 * @filename: the path to a file
3792 *
3793 * lookup the directory for that file
3794 *
3795 * Returns a new allocated string containing the directory, or NULL.
3796 */
3797char *
3798xmlParserGetDirectory(const char *filename) {
3799 char *ret = NULL;
3800 char dir[1024];
3801 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003802
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003803#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3804 return NULL;
3805#endif
3806
Owen Taylor3473f882001-02-23 17:55:21 +00003807 if (xmlInputCallbackInitialized == 0)
3808 xmlRegisterDefaultInputCallbacks();
3809
3810 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003811
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003812#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003813# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3814#else
3815# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003816#endif
3817
3818 strncpy(dir, filename, 1023);
3819 dir[1023] = 0;
3820 cur = &dir[strlen(dir)];
3821 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003822 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003823 cur --;
3824 }
Rob Richardsf779da32007-08-14 09:41:21 +00003825 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003826 if (cur == dir) dir[1] = 0;
3827 else *cur = 0;
3828 ret = xmlMemStrdup(dir);
3829 } else {
3830 if (getcwd(dir, 1024) != NULL) {
3831 dir[1023] = 0;
3832 ret = xmlMemStrdup(dir);
3833 }
3834 }
3835 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003836#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003837}
3838
3839/****************************************************************
3840 * *
3841 * External entities loading *
3842 * *
3843 ****************************************************************/
3844
Daniel Veillarda840b692003-10-19 13:35:37 +00003845/**
3846 * xmlCheckHTTPInput:
3847 * @ctxt: an XML parser context
3848 * @ret: an XML parser input
3849 *
3850 * Check an input in case it was created from an HTTP stream, in that
3851 * case it will handle encoding and update of the base URL in case of
3852 * redirection. It also checks for HTTP errors in which case the input
3853 * is cleanly freed up and an appropriate error is raised in context
3854 *
3855 * Returns the input or NULL in case of HTTP error.
3856 */
3857xmlParserInputPtr
3858xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3859#ifdef LIBXML_HTTP_ENABLED
3860 if ((ret != NULL) && (ret->buf != NULL) &&
3861 (ret->buf->readcallback == xmlIOHTTPRead) &&
3862 (ret->buf->context != NULL)) {
3863 const char *encoding;
3864 const char *redir;
3865 const char *mime;
3866 int code;
3867
3868 code = xmlNanoHTTPReturnCode(ret->buf->context);
3869 if (code >= 400) {
3870 /* fatal error */
3871 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003872 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003873 (const char *) ret->filename);
3874 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003875 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003876 xmlFreeInputStream(ret);
3877 ret = NULL;
3878 } else {
3879
3880 mime = xmlNanoHTTPMimeType(ret->buf->context);
3881 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3882 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3883 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3884 if (encoding != NULL) {
3885 xmlCharEncodingHandlerPtr handler;
3886
3887 handler = xmlFindCharEncodingHandler(encoding);
3888 if (handler != NULL) {
3889 xmlSwitchInputEncoding(ctxt, ret, handler);
3890 } else {
3891 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3892 "Unknown encoding %s",
3893 BAD_CAST encoding, NULL);
3894 }
3895 if (ret->encoding == NULL)
3896 ret->encoding = xmlStrdup(BAD_CAST encoding);
3897 }
3898#if 0
3899 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3900#endif
3901 }
3902 redir = xmlNanoHTTPRedir(ret->buf->context);
3903 if (redir != NULL) {
3904 if (ret->filename != NULL)
3905 xmlFree((xmlChar *) ret->filename);
3906 if (ret->directory != NULL) {
3907 xmlFree((xmlChar *) ret->directory);
3908 ret->directory = NULL;
3909 }
3910 ret->filename =
3911 (char *) xmlStrdup((const xmlChar *) redir);
3912 }
3913 }
3914 }
3915#endif
3916 return(ret);
3917}
3918
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003919static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003920 const char *path;
3921
3922 if (URL == NULL)
3923 return(0);
3924
Daniel Veillardf4862f02002-09-10 11:13:43 +00003925 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003926#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003927 path = &URL[17];
3928#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003929 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003930#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003931 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003932#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003933 path = &URL[8];
3934#else
3935 path = &URL[7];
3936#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003937 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003938 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003939
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003940 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003941}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003942
Daniel Veillardad4e2962006-09-21 08:36:38 +00003943#ifdef LIBXML_CATALOG_ENABLED
3944
3945/**
3946 * xmlResolveResourceFromCatalog:
3947 * @URL: the URL for the entity to load
3948 * @ID: the System ID for the entity to load
3949 * @ctxt: the context in which the entity is called or NULL
3950 *
3951 * Resolves the URL and ID against the appropriate catalog.
3952 * This function is used by xmlDefaultExternalEntityLoader and
3953 * xmlNoNetExternalEntityLoader.
3954 *
3955 * Returns a new allocated URL, or NULL.
3956 */
William M. Brack38d452a2007-05-22 16:00:06 +00003957static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003958xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3959 xmlParserCtxtPtr ctxt) {
3960 xmlChar *resource = NULL;
3961 xmlCatalogAllow pref;
3962
3963 /*
3964 * If the resource doesn't exists as a file,
3965 * try to load it from the resource pointed in the catalogs
3966 */
3967 pref = xmlCatalogGetDefaults();
3968
3969 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3970 /*
3971 * Do a local lookup
3972 */
3973 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3974 ((pref == XML_CATA_ALLOW_ALL) ||
3975 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3976 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3977 (const xmlChar *)ID,
3978 (const xmlChar *)URL);
3979 }
3980 /*
3981 * Try a global lookup
3982 */
3983 if ((resource == NULL) &&
3984 ((pref == XML_CATA_ALLOW_ALL) ||
3985 (pref == XML_CATA_ALLOW_GLOBAL))) {
3986 resource = xmlCatalogResolve((const xmlChar *)ID,
3987 (const xmlChar *)URL);
3988 }
3989 if ((resource == NULL) && (URL != NULL))
3990 resource = xmlStrdup((const xmlChar *) URL);
3991
3992 /*
3993 * TODO: do an URI lookup on the reference
3994 */
3995 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3996 xmlChar *tmp = NULL;
3997
3998 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3999 ((pref == XML_CATA_ALLOW_ALL) ||
4000 (pref == XML_CATA_ALLOW_DOCUMENT))) {
4001 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
4002 }
4003 if ((tmp == NULL) &&
4004 ((pref == XML_CATA_ALLOW_ALL) ||
4005 (pref == XML_CATA_ALLOW_GLOBAL))) {
4006 tmp = xmlCatalogResolveURI(resource);
4007 }
4008
4009 if (tmp != NULL) {
4010 xmlFree(resource);
4011 resource = tmp;
4012 }
4013 }
4014 }
4015
4016 return resource;
4017}
4018
4019#endif
4020
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004021/**
Owen Taylor3473f882001-02-23 17:55:21 +00004022 * xmlDefaultExternalEntityLoader:
4023 * @URL: the URL for the entity to load
4024 * @ID: the System ID for the entity to load
4025 * @ctxt: the context in which the entity is called or NULL
4026 *
4027 * By default we don't load external entitites, yet.
4028 *
4029 * Returns a new allocated xmlParserInputPtr, or NULL.
4030 */
Daniel Veillarda840b692003-10-19 13:35:37 +00004031static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00004032xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00004033 xmlParserCtxtPtr ctxt)
4034{
Owen Taylor3473f882001-02-23 17:55:21 +00004035 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00004036 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00004037
Owen Taylor3473f882001-02-23 17:55:21 +00004038#ifdef DEBUG_EXTERNAL_ENTITIES
4039 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00004040 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004041#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00004042 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
4043 int options = ctxt->options;
4044
4045 ctxt->options -= XML_PARSE_NONET;
4046 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4047 ctxt->options = options;
4048 return(ret);
4049 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00004050#ifdef LIBXML_CATALOG_ENABLED
4051 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004052#endif
4053
4054 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004055 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004056
4057 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004058 if (ID == NULL)
4059 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004060 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004061 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004062 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004063 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004064 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004065 xmlFree(resource);
4066 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004067}
4068
4069static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4070 xmlDefaultExternalEntityLoader;
4071
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004072/**
Owen Taylor3473f882001-02-23 17:55:21 +00004073 * xmlSetExternalEntityLoader:
4074 * @f: the new entity resolver function
4075 *
4076 * Changes the defaultexternal entity resolver function for the application
4077 */
4078void
4079xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4080 xmlCurrentExternalEntityLoader = f;
4081}
4082
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004083/**
Owen Taylor3473f882001-02-23 17:55:21 +00004084 * xmlGetExternalEntityLoader:
4085 *
4086 * Get the default external entity resolver function for the application
4087 *
4088 * Returns the xmlExternalEntityLoader function pointer
4089 */
4090xmlExternalEntityLoader
4091xmlGetExternalEntityLoader(void) {
4092 return(xmlCurrentExternalEntityLoader);
4093}
4094
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004095/**
Owen Taylor3473f882001-02-23 17:55:21 +00004096 * xmlLoadExternalEntity:
4097 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004098 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004099 * @ctxt: the context in which the entity is called or NULL
4100 *
4101 * Load an external entity, note that the use of this function for
4102 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004103 *
4104 * Returns the xmlParserInputPtr or NULL
4105 */
4106xmlParserInputPtr
4107xmlLoadExternalEntity(const char *URL, const char *ID,
4108 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004109 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004110 char *canonicFilename;
4111 xmlParserInputPtr ret;
4112
4113 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4114 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004115 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004116 return(NULL);
4117 }
4118
4119 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4120 xmlFree(canonicFilename);
4121 return(ret);
4122 }
Owen Taylor3473f882001-02-23 17:55:21 +00004123 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4124}
4125
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004126/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004127 * *
4128 * Disabling Network access *
4129 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004130 ************************************************************************/
4131
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004132/**
4133 * xmlNoNetExternalEntityLoader:
4134 * @URL: the URL for the entity to load
4135 * @ID: the System ID for the entity to load
4136 * @ctxt: the context in which the entity is called or NULL
4137 *
4138 * A specific entity loader disabling network accesses, though still
4139 * allowing local catalog accesses for resolution.
4140 *
4141 * Returns a new allocated xmlParserInputPtr, or NULL.
4142 */
4143xmlParserInputPtr
4144xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4145 xmlParserCtxtPtr ctxt) {
4146 xmlParserInputPtr input = NULL;
4147 xmlChar *resource = NULL;
4148
4149#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004150 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004151#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004152
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004153 if (resource == NULL)
4154 resource = (xmlChar *) URL;
4155
4156 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004157 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4158 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004159 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004160 if (resource != (xmlChar *) URL)
4161 xmlFree(resource);
4162 return(NULL);
4163 }
4164 }
4165 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4166 if (resource != (xmlChar *) URL)
4167 xmlFree(resource);
4168 return(input);
4169}
4170
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004171#define bottom_xmlIO
4172#include "elfgcchack.h"