blob: fecdae56f34b9885995502206754901d12c1c700 [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, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001162 fd = gzdopen(dup(0), "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, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001236 fd = gzdopen(dup(1), 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, "-")) {
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001358 fd = __libxml2_xzdopen(dup(0), "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
Owen Taylor3473f882001-02-23 17:55:21 +00002672 }
William M. Brack42331a92004-07-29 07:07:16 +00002673 else
2674 xmlInputCallbackTable[i].closecallback (context);
2675
Owen Taylor3473f882001-02-23 17:55:21 +00002676 return(ret);
2677}
2678
2679/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002680 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002681 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002682 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002683 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002684 * Create a buffered parser input for the progressive parsing of a file
2685 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002686 * Automatic support for ZLIB/Compress compressed document is provided
2687 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002688 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002689 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002690 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002691 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002692xmlParserInputBufferPtr
2693xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2694 if ((xmlParserInputBufferCreateFilenameValue)) {
2695 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2696 }
2697 return __xmlParserInputBufferCreateFilename(URI, enc);
2698}
2699
2700#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002701xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002702__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002703 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002704 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002705 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002706 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002707 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002708 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002709 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002710#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002711 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002712#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002713
Owen Taylor3473f882001-02-23 17:55:21 +00002714 if (xmlOutputCallbackInitialized == 0)
2715 xmlRegisterDefaultOutputCallbacks();
2716
2717 if (URI == NULL) return(NULL);
2718
Daniel Veillard966a31e2004-05-09 02:58:44 +00002719 puri = xmlParseURI(URI);
2720 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002721#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002722 if ((puri->scheme != NULL) &&
2723 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002724 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002725#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002726 /*
2727 * try to limit the damages of the URI unescaping code.
2728 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002729 if ((puri->scheme == NULL) ||
2730 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002731 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2732 xmlFreeURI(puri);
2733 }
Owen Taylor3473f882001-02-23 17:55:21 +00002734
2735 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002736 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002737 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002738 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002739 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002740 if (unescaped != NULL) {
2741#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002742 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002743 context = xmlGzfileOpenW(unescaped, compression);
2744 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002745 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002746 if (ret != NULL) {
2747 ret->context = context;
2748 ret->writecallback = xmlGzfileWrite;
2749 ret->closecallback = xmlGzfileClose;
2750 }
2751 xmlFree(unescaped);
2752 return(ret);
2753 }
2754 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002755#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002756 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2757 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2758 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2759#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2760 /* Need to pass compression parameter into HTTP open calls */
2761 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2762 context = xmlIOHTTPOpenW(unescaped, compression);
2763 else
2764#endif
2765 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2766 if (context != NULL)
2767 break;
2768 }
2769 }
2770 xmlFree(unescaped);
2771 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002772
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002773 /*
2774 * If this failed try with a non-escaped URI this may be a strange
2775 * filename
2776 */
2777 if (context == NULL) {
2778#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002779 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002780 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002781 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002782 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002783 if (ret != NULL) {
2784 ret->context = context;
2785 ret->writecallback = xmlGzfileWrite;
2786 ret->closecallback = xmlGzfileClose;
2787 }
2788 return(ret);
2789 }
2790 }
2791#endif
2792 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2793 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002794 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002795#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2796 /* Need to pass compression parameter into HTTP open calls */
2797 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2798 context = xmlIOHTTPOpenW(URI, compression);
2799 else
2800#endif
2801 context = xmlOutputCallbackTable[i].opencallback(URI);
2802 if (context != NULL)
2803 break;
2804 }
Owen Taylor3473f882001-02-23 17:55:21 +00002805 }
2806 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002807
Owen Taylor3473f882001-02-23 17:55:21 +00002808 if (context == NULL) {
2809 return(NULL);
2810 }
2811
2812 /*
2813 * Allocate the Output buffer front-end.
2814 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002815 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002816 if (ret != NULL) {
2817 ret->context = context;
2818 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2819 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2820 }
2821 return(ret);
2822}
Daniel Veillard0335a842004-06-02 16:18:40 +00002823
2824/**
2825 * xmlOutputBufferCreateFilename:
2826 * @URI: a C string containing the URI or filename
2827 * @encoder: the encoding converter or NULL
2828 * @compression: the compression ration (0 none, 9 max).
2829 *
2830 * Create a buffered output for the progressive saving of a file
2831 * If filename is "-' then we use stdout as the output.
2832 * Automatic support for ZLIB/Compress compressed document is provided
2833 * by default if found at compile-time.
2834 * TODO: currently if compression is set, the library only support
2835 * writing to a local file.
2836 *
2837 * Returns the new output or NULL
2838 */
2839xmlOutputBufferPtr
2840xmlOutputBufferCreateFilename(const char *URI,
2841 xmlCharEncodingHandlerPtr encoder,
2842 int compression ATTRIBUTE_UNUSED) {
2843 if ((xmlOutputBufferCreateFilenameValue)) {
2844 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2845 }
2846 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2847}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002848#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002849
2850/**
2851 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002852 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002853 * @enc: the charset encoding if known
2854 *
2855 * Create a buffered parser input for the progressive parsing of a FILE *
2856 * buffered C I/O
2857 *
2858 * Returns the new parser input or NULL
2859 */
2860xmlParserInputBufferPtr
2861xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2862 xmlParserInputBufferPtr ret;
2863
2864 if (xmlInputCallbackInitialized == 0)
2865 xmlRegisterDefaultInputCallbacks();
2866
2867 if (file == NULL) return(NULL);
2868
2869 ret = xmlAllocParserInputBuffer(enc);
2870 if (ret != NULL) {
2871 ret->context = file;
2872 ret->readcallback = xmlFileRead;
2873 ret->closecallback = xmlFileFlush;
2874 }
2875
2876 return(ret);
2877}
2878
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002879#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002880/**
2881 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002882 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002883 * @encoder: the encoding converter or NULL
2884 *
2885 * Create a buffered output for the progressive saving to a FILE *
2886 * buffered C I/O
2887 *
2888 * Returns the new parser output or NULL
2889 */
2890xmlOutputBufferPtr
2891xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2892 xmlOutputBufferPtr ret;
2893
2894 if (xmlOutputCallbackInitialized == 0)
2895 xmlRegisterDefaultOutputCallbacks();
2896
2897 if (file == NULL) return(NULL);
2898
Daniel Veillardda3fee42008-09-01 13:08:57 +00002899 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002900 if (ret != NULL) {
2901 ret->context = file;
2902 ret->writecallback = xmlFileWrite;
2903 ret->closecallback = xmlFileFlush;
2904 }
2905
2906 return(ret);
2907}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002908
2909/**
2910 * xmlOutputBufferCreateBuffer:
2911 * @buffer: a xmlBufferPtr
2912 * @encoder: the encoding converter or NULL
2913 *
2914 * Create a buffered output for the progressive saving to a xmlBuffer
2915 *
2916 * Returns the new parser output or NULL
2917 */
2918xmlOutputBufferPtr
2919xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2920 xmlCharEncodingHandlerPtr encoder) {
2921 xmlOutputBufferPtr ret;
2922
2923 if (buffer == NULL) return(NULL);
2924
Rob Richardsa44f2342005-11-09 18:03:45 +00002925 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2926 xmlBufferWrite,
2927 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002928 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002929
2930 return(ret);
2931}
2932
Daniel Veillarde258ade2012-08-06 11:16:30 +08002933/**
2934 * xmlOutputBufferGetContent:
2935 * @out: an xmlOutputBufferPtr
2936 *
2937 * Gives a pointer to the data currently held in the output buffer
2938 *
2939 * Returns a pointer to the data or NULL in case of error
2940 */
2941const xmlChar *
2942xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2943 if ((out == NULL) || (out->buffer == NULL))
2944 return(NULL);
2945
2946 return(xmlBufContent(out->buffer));
2947}
2948
2949/**
2950 * xmlOutputBufferGetSize:
2951 * @out: an xmlOutputBufferPtr
2952 *
2953 * Gives the length of the data currently held in the output buffer
2954 *
2955 * Returns 0 in case or error or no data is held, the size otherwise
2956 */
2957size_t
2958xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2959 if ((out == NULL) || (out->buffer == NULL))
2960 return(0);
2961
2962 return(xmlBufUse(out->buffer));
2963}
2964
2965
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002966#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002967
2968/**
2969 * xmlParserInputBufferCreateFd:
2970 * @fd: a file descriptor number
2971 * @enc: the charset encoding if known
2972 *
2973 * Create a buffered parser input for the progressive parsing for the input
2974 * from a file descriptor
2975 *
2976 * Returns the new parser input or NULL
2977 */
2978xmlParserInputBufferPtr
2979xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2980 xmlParserInputBufferPtr ret;
2981
2982 if (fd < 0) return(NULL);
2983
2984 ret = xmlAllocParserInputBuffer(enc);
2985 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002986 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002987 ret->readcallback = xmlFdRead;
2988 ret->closecallback = xmlFdClose;
2989 }
2990
2991 return(ret);
2992}
2993
2994/**
2995 * xmlParserInputBufferCreateMem:
2996 * @mem: the memory input
2997 * @size: the length of the memory block
2998 * @enc: the charset encoding if known
2999 *
3000 * Create a buffered parser input for the progressive parsing for the input
3001 * from a memory area.
3002 *
3003 * Returns the new parser input or NULL
3004 */
3005xmlParserInputBufferPtr
3006xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
3007 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00003008 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00003009
3010 if (size <= 0) return(NULL);
3011 if (mem == NULL) return(NULL);
3012
3013 ret = xmlAllocParserInputBuffer(enc);
3014 if (ret != NULL) {
3015 ret->context = (void *) mem;
3016 ret->readcallback = (xmlInputReadCallback) xmlNop;
3017 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003018 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00003019 if (errcode != 0) {
3020 xmlFree(ret);
3021 return(NULL);
3022 }
Owen Taylor3473f882001-02-23 17:55:21 +00003023 }
3024
3025 return(ret);
3026}
3027
3028/**
Daniel Veillard53350552003-09-18 13:35:51 +00003029 * xmlParserInputBufferCreateStatic:
3030 * @mem: the memory input
3031 * @size: the length of the memory block
3032 * @enc: the charset encoding if known
3033 *
3034 * Create a buffered parser input for the progressive parsing for the input
3035 * from an immutable memory area. This will not copy the memory area to
3036 * the buffer, but the memory is expected to be available until the end of
3037 * the parsing, this is useful for example when using mmap'ed file.
3038 *
3039 * Returns the new parser input or NULL
3040 */
3041xmlParserInputBufferPtr
3042xmlParserInputBufferCreateStatic(const char *mem, int size,
3043 xmlCharEncoding enc) {
3044 xmlParserInputBufferPtr ret;
3045
3046 if (size <= 0) return(NULL);
3047 if (mem == NULL) return(NULL);
3048
3049 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3050 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003051 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003052 return(NULL);
3053 }
3054 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003055 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003056 if (ret->buffer == NULL) {
3057 xmlFree(ret);
3058 return(NULL);
3059 }
3060 ret->encoder = xmlGetCharEncodingHandler(enc);
3061 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003062 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00003063 else
3064 ret->raw = NULL;
3065 ret->compressed = -1;
3066 ret->context = (void *) mem;
3067 ret->readcallback = NULL;
3068 ret->closecallback = NULL;
3069
3070 return(ret);
3071}
3072
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003073#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003074/**
Owen Taylor3473f882001-02-23 17:55:21 +00003075 * xmlOutputBufferCreateFd:
3076 * @fd: a file descriptor number
3077 * @encoder: the encoding converter or NULL
3078 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003079 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003080 * to a file descriptor
3081 *
3082 * Returns the new parser output or NULL
3083 */
3084xmlOutputBufferPtr
3085xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3086 xmlOutputBufferPtr ret;
3087
3088 if (fd < 0) return(NULL);
3089
Daniel Veillardda3fee42008-09-01 13:08:57 +00003090 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003091 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003092 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003093 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003094 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003095 }
3096
3097 return(ret);
3098}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003099#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003100
3101/**
3102 * xmlParserInputBufferCreateIO:
3103 * @ioread: an I/O read function
3104 * @ioclose: an I/O close function
3105 * @ioctx: an I/O handler
3106 * @enc: the charset encoding if known
3107 *
3108 * Create a buffered parser input for the progressive parsing for the input
3109 * from an I/O handler
3110 *
3111 * Returns the new parser input or NULL
3112 */
3113xmlParserInputBufferPtr
3114xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3115 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3116 xmlParserInputBufferPtr ret;
3117
3118 if (ioread == NULL) return(NULL);
3119
3120 ret = xmlAllocParserInputBuffer(enc);
3121 if (ret != NULL) {
3122 ret->context = (void *) ioctx;
3123 ret->readcallback = ioread;
3124 ret->closecallback = ioclose;
3125 }
3126
3127 return(ret);
3128}
3129
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003130#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003131/**
3132 * xmlOutputBufferCreateIO:
3133 * @iowrite: an I/O write function
3134 * @ioclose: an I/O close function
3135 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003136 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003137 *
3138 * Create a buffered output for the progressive saving
3139 * to an I/O handler
3140 *
3141 * Returns the new parser output or NULL
3142 */
3143xmlOutputBufferPtr
3144xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3145 xmlOutputCloseCallback ioclose, void *ioctx,
3146 xmlCharEncodingHandlerPtr encoder) {
3147 xmlOutputBufferPtr ret;
3148
3149 if (iowrite == NULL) return(NULL);
3150
Daniel Veillardda3fee42008-09-01 13:08:57 +00003151 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003152 if (ret != NULL) {
3153 ret->context = (void *) ioctx;
3154 ret->writecallback = iowrite;
3155 ret->closecallback = ioclose;
3156 }
3157
3158 return(ret);
3159}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003160#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003161
3162/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003163 * xmlParserInputBufferCreateFilenameDefault:
3164 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3165 *
3166 * Registers a callback for URI input file handling
3167 *
3168 * Returns the old value of the registration function
3169 */
3170xmlParserInputBufferCreateFilenameFunc
3171xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3172{
3173 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3174 if (old == NULL) {
3175 old = __xmlParserInputBufferCreateFilename;
3176 }
3177
3178 xmlParserInputBufferCreateFilenameValue = func;
3179 return(old);
3180}
3181
3182/**
3183 * xmlOutputBufferCreateFilenameDefault:
3184 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3185 *
3186 * Registers a callback for URI output file handling
3187 *
3188 * Returns the old value of the registration function
3189 */
3190xmlOutputBufferCreateFilenameFunc
3191xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3192{
3193 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3194#ifdef LIBXML_OUTPUT_ENABLED
3195 if (old == NULL) {
3196 old = __xmlOutputBufferCreateFilename;
3197 }
3198#endif
3199 xmlOutputBufferCreateFilenameValue = func;
3200 return(old);
3201}
3202
3203/**
Owen Taylor3473f882001-02-23 17:55:21 +00003204 * xmlParserInputBufferPush:
3205 * @in: a buffered parser input
3206 * @len: the size in bytes of the array.
3207 * @buf: an char array
3208 *
3209 * Push the content of the arry in the input buffer
3210 * This routine handle the I18N transcoding to internal UTF-8
3211 * This is used when operating the parser in progressive (push) mode.
3212 *
3213 * Returns the number of chars read and stored in the buffer, or -1
3214 * in case of error.
3215 */
3216int
3217xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3218 int len, const char *buf) {
3219 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003220 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003221
3222 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003223 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003224 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003225 unsigned int use;
3226
Owen Taylor3473f882001-02-23 17:55:21 +00003227 /*
3228 * Store the data in the incoming raw buffer
3229 */
3230 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003231 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003232 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003233 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003234 if (ret != 0)
3235 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003236
3237 /*
3238 * convert as much as possible to the parser reading buffer.
3239 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003240 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003241 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003242 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003243 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003244 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003245 return(-1);
3246 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003247 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003248 } else {
3249 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003250 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003251 if (ret != 0)
3252 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003253 }
3254#ifdef DEBUG_INPUT
3255 xmlGenericError(xmlGenericErrorContext,
3256 "I/O: pushed %d chars, buffer %d/%d\n",
Roumen Petrov89b6f732012-08-04 05:09:56 +03003257 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003258#endif
3259 return(nbchars);
3260}
3261
3262/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003263 * endOfInput:
3264 *
3265 * When reading from an Input channel indicated end of file or error
3266 * don't reread from it again.
3267 */
3268static int
3269endOfInput (void * context ATTRIBUTE_UNUSED,
3270 char * buffer ATTRIBUTE_UNUSED,
3271 int len ATTRIBUTE_UNUSED) {
3272 return(0);
3273}
3274
3275/**
Owen Taylor3473f882001-02-23 17:55:21 +00003276 * xmlParserInputBufferGrow:
3277 * @in: a buffered parser input
3278 * @len: indicative value of the amount of chars to read
3279 *
3280 * Grow up the content of the input buffer, the old data are preserved
3281 * This routine handle the I18N transcoding to internal UTF-8
3282 * This routine is used when operating the parser in normal (pull) mode
3283 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003284 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003285 * onto in->buffer or in->raw
3286 *
3287 * Returns the number of chars read and stored in the buffer, or -1
3288 * in case of error.
3289 */
3290int
3291xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3292 char *buffer = NULL;
3293 int res = 0;
3294 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003295
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003296 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003297 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003298 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003299
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003300 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003301 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003302 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003303 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003304 }
Owen Taylor3473f882001-02-23 17:55:21 +00003305
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003306 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3307 xmlIOErrMemory("growing input buffer");
3308 in->error = XML_ERR_NO_MEMORY;
3309 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003310 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003311 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003312
3313 /*
3314 * Call the read method for this I/O type.
3315 */
3316 if (in->readcallback != NULL) {
3317 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003318 if (res <= 0)
3319 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003320 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003321 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003322 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003323 return(-1);
3324 }
3325 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003326 return(-1);
3327 }
3328 len = res;
3329 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003330 unsigned int use;
3331
Owen Taylor3473f882001-02-23 17:55:21 +00003332 /*
3333 * Store the data in the incoming raw buffer
3334 */
3335 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003336 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003337 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003338 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003339 if (res != 0)
3340 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003341
3342 /*
3343 * convert as much as possible to the parser reading buffer.
3344 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003345 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003346 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003347 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003348 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003349 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003350 return(-1);
3351 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003352 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003353 } else {
3354 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003355 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003356 }
3357#ifdef DEBUG_INPUT
3358 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003359 "I/O: read %d chars, buffer %d\n",
3360 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003361#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003362 return(nbchars);
3363}
3364
3365/**
3366 * xmlParserInputBufferRead:
3367 * @in: a buffered parser input
3368 * @len: indicative value of the amount of chars to read
3369 *
3370 * Refresh the content of the input buffer, the old data are considered
3371 * consumed
3372 * This routine handle the I18N transcoding to internal UTF-8
3373 *
3374 * Returns the number of chars read and stored in the buffer, or -1
3375 * in case of error.
3376 */
3377int
3378xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003379 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003380 if (in->readcallback != NULL)
3381 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003382 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003383 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003384 else
3385 return(-1);
3386}
3387
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003388#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003389/**
3390 * xmlOutputBufferWrite:
3391 * @out: a buffered parser output
3392 * @len: the size in bytes of the array.
3393 * @buf: an char array
3394 *
3395 * Write the content of the array in the output I/O buffer
3396 * This routine handle the I18N transcoding from internal UTF-8
3397 * The buffer is lossless, i.e. will store in case of partial
3398 * or delayed writes.
3399 *
3400 * Returns the number of chars immediately written, or -1
3401 * in case of error.
3402 */
3403int
3404xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3405 int nbchars = 0; /* number of chars to output to I/O */
3406 int ret; /* return from function call */
3407 int written = 0; /* number of char written to I/O so far */
3408 int chunk; /* number of byte curreent processed from buf */
3409
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003410 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003411 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003412 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003413
3414 do {
3415 chunk = len;
3416 if (chunk > 4 * MINLEN)
3417 chunk = 4 * MINLEN;
3418
3419 /*
3420 * first handle encoding stuff.
3421 */
3422 if (out->encoder != NULL) {
3423 /*
3424 * Store the data in the incoming raw buffer
3425 */
3426 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003427 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003428 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003429 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003430 if (ret != 0)
3431 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003432
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003433 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003434 goto done;
3435
3436 /*
3437 * convert as much as possible to the parser reading buffer.
3438 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003439 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003440 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003441 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003442 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003443 return(-1);
3444 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003445 nbchars = xmlBufUse(out->conv);
Owen Taylor3473f882001-02-23 17:55:21 +00003446 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003447 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003448 if (ret != 0)
3449 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003450 nbchars = xmlBufUse(out->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003451 }
3452 buf += chunk;
3453 len -= chunk;
3454
3455 if ((nbchars < MINLEN) && (len <= 0))
3456 goto done;
3457
3458 if (out->writecallback) {
3459 /*
3460 * second write the stuff to the I/O channel
3461 */
3462 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003463 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003464 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003465 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003466 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003467 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003468 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003469 (const char *)xmlBufContent(out->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003470 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003471 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003472 }
3473 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003474 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003475 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003476 return(ret);
3477 }
3478 out->written += ret;
3479 }
3480 written += nbchars;
3481 } while (len > 0);
3482
3483done:
3484#ifdef DEBUG_INPUT
3485 xmlGenericError(xmlGenericErrorContext,
3486 "I/O: wrote %d chars\n", written);
3487#endif
3488 return(written);
3489}
3490
3491/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003492 * xmlEscapeContent:
3493 * @out: a pointer to an array of bytes to store the result
3494 * @outlen: the length of @out
3495 * @in: a pointer to an array of unescaped UTF-8 bytes
3496 * @inlen: the length of @in
3497 *
3498 * Take a block of UTF-8 chars in and escape them.
3499 * Returns 0 if success, or -1 otherwise
3500 * The value of @inlen after return is the number of octets consumed
3501 * if the return value is positive, else unpredictable.
3502 * The value of @outlen after return is the number of octets consumed.
3503 */
3504static int
3505xmlEscapeContent(unsigned char* out, int *outlen,
3506 const xmlChar* in, int *inlen) {
3507 unsigned char* outstart = out;
3508 const unsigned char* base = in;
3509 unsigned char* outend = out + *outlen;
3510 const unsigned char* inend;
3511
3512 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003513
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003514 while ((in < inend) && (out < outend)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003515 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003516 if (outend - out < 4) break;
3517 *out++ = '&';
3518 *out++ = 'l';
3519 *out++ = 't';
3520 *out++ = ';';
3521 } else if (*in == '>') {
3522 if (outend - out < 4) break;
3523 *out++ = '&';
3524 *out++ = 'g';
3525 *out++ = 't';
3526 *out++ = ';';
3527 } else if (*in == '&') {
3528 if (outend - out < 5) break;
3529 *out++ = '&';
3530 *out++ = 'a';
3531 *out++ = 'm';
3532 *out++ = 'p';
3533 *out++ = ';';
3534 } else if (*in == '\r') {
3535 if (outend - out < 5) break;
3536 *out++ = '&';
3537 *out++ = '#';
3538 *out++ = '1';
3539 *out++ = '3';
3540 *out++ = ';';
3541 } else {
3542 *out++ = (unsigned char) *in;
3543 }
3544 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003545 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003546 *outlen = out - outstart;
3547 *inlen = in - base;
3548 return(0);
3549}
3550
3551/**
3552 * xmlOutputBufferWriteEscape:
3553 * @out: a buffered parser output
3554 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003555 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003556 *
3557 * Write the content of the string in the output I/O buffer
3558 * This routine escapes the caracters and then handle the I18N
3559 * transcoding from internal UTF-8
3560 * The buffer is lossless, i.e. will store in case of partial
3561 * or delayed writes.
3562 *
3563 * Returns the number of chars immediately written, or -1
3564 * in case of error.
3565 */
3566int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003567xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3568 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003569 int nbchars = 0; /* number of chars to output to I/O */
3570 int ret; /* return from function call */
3571 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003572 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003573 int chunk; /* number of byte currently processed from str */
3574 int len; /* number of bytes in str */
3575 int cons; /* byte from str consumed */
3576
Daniel Veillardce244ad2004-11-05 10:03:46 +00003577 if ((out == NULL) || (out->error) || (str == NULL) ||
3578 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003579 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3580 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003581 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003582 if (len < 0) return(0);
3583 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003584 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003585
3586 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003587 oldwritten = written;
3588
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003589 /*
3590 * how many bytes to consume and how many bytes to store.
3591 */
3592 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003593 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003594
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003595 /*
3596 * make sure we have enough room to save first, if this is
3597 * not the case force a flush, but make sure we stay in the loop
3598 */
3599 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003600 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003601 return(-1);
3602 oldwritten = -1;
3603 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003604 }
3605
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003606 /*
3607 * first handle encoding stuff.
3608 */
3609 if (out->encoder != NULL) {
3610 /*
3611 * Store the data in the incoming raw buffer
3612 */
3613 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003614 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003615 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003616 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003617 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003618 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003619 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003620 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003621
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003622 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003623 goto done;
3624
3625 /*
3626 * convert as much as possible to the output buffer.
3627 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003628 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003629 if ((ret < 0) && (ret != -3)) {
3630 xmlIOErr(XML_IO_ENCODER, NULL);
3631 out->error = XML_IO_ENCODER;
3632 return(-1);
3633 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003634 nbchars = xmlBufUse(out->conv);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003635 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003636 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003637 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003638 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003639 xmlBufAddLen(out->buffer, chunk);
3640 nbchars = xmlBufUse(out->buffer);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003641 }
3642 str += cons;
3643 len -= cons;
3644
3645 if ((nbchars < MINLEN) && (len <= 0))
3646 goto done;
3647
3648 if (out->writecallback) {
3649 /*
3650 * second write the stuff to the I/O channel
3651 */
3652 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003653 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003654 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003655 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003656 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003657 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003658 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003659 (const char *)xmlBufContent(out->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003660 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003661 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003662 }
3663 if (ret < 0) {
3664 xmlIOErr(XML_IO_WRITE, NULL);
3665 out->error = XML_IO_WRITE;
3666 return(ret);
3667 }
3668 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003669 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3670 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003671 }
3672 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003673 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003674
3675done:
3676#ifdef DEBUG_INPUT
3677 xmlGenericError(xmlGenericErrorContext,
3678 "I/O: wrote %d chars\n", written);
3679#endif
3680 return(written);
3681}
3682
3683/**
Owen Taylor3473f882001-02-23 17:55:21 +00003684 * xmlOutputBufferWriteString:
3685 * @out: a buffered parser output
3686 * @str: a zero terminated C string
3687 *
3688 * Write the content of the string in the output I/O buffer
3689 * This routine handle the I18N transcoding from internal UTF-8
3690 * The buffer is lossless, i.e. will store in case of partial
3691 * or delayed writes.
3692 *
3693 * Returns the number of chars immediately written, or -1
3694 * in case of error.
3695 */
3696int
3697xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3698 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003699
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003700 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003701 if (str == NULL)
3702 return(-1);
3703 len = strlen(str);
3704
3705 if (len > 0)
3706 return(xmlOutputBufferWrite(out, len, str));
3707 return(len);
3708}
3709
3710/**
3711 * xmlOutputBufferFlush:
3712 * @out: a buffered output
3713 *
3714 * flushes the output I/O channel
3715 *
3716 * Returns the number of byte written or -1 in case of error.
3717 */
3718int
3719xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3720 int nbchars = 0, ret = 0;
3721
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003722 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003723 /*
3724 * first handle encoding stuff.
3725 */
3726 if ((out->conv != NULL) && (out->encoder != NULL)) {
3727 /*
3728 * convert as much as possible to the parser reading buffer.
3729 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003730 nbchars = xmlCharEncOutput(out, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00003731 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003732 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003733 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003734 return(-1);
3735 }
3736 }
3737
3738 /*
3739 * second flush the stuff to the I/O channel
3740 */
3741 if ((out->conv != NULL) && (out->encoder != NULL) &&
3742 (out->writecallback != NULL)) {
3743 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003744 (const char *)xmlBufContent(out->conv),
3745 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003746 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003747 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003748 } else if (out->writecallback != NULL) {
3749 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003750 (const char *)xmlBufContent(out->buffer),
3751 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003752 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003753 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003754 }
3755 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003756 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003757 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003758 return(ret);
3759 }
3760 out->written += ret;
3761
3762#ifdef DEBUG_INPUT
3763 xmlGenericError(xmlGenericErrorContext,
3764 "I/O: flushed %d chars\n", ret);
3765#endif
3766 return(ret);
3767}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003768#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003769
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003770/**
Owen Taylor3473f882001-02-23 17:55:21 +00003771 * xmlParserGetDirectory:
3772 * @filename: the path to a file
3773 *
3774 * lookup the directory for that file
3775 *
3776 * Returns a new allocated string containing the directory, or NULL.
3777 */
3778char *
3779xmlParserGetDirectory(const char *filename) {
3780 char *ret = NULL;
3781 char dir[1024];
3782 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003783
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003784#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3785 return NULL;
3786#endif
3787
Owen Taylor3473f882001-02-23 17:55:21 +00003788 if (xmlInputCallbackInitialized == 0)
3789 xmlRegisterDefaultInputCallbacks();
3790
3791 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003792
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003793#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003794# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3795#else
3796# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003797#endif
3798
3799 strncpy(dir, filename, 1023);
3800 dir[1023] = 0;
3801 cur = &dir[strlen(dir)];
3802 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003803 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003804 cur --;
3805 }
Rob Richardsf779da32007-08-14 09:41:21 +00003806 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003807 if (cur == dir) dir[1] = 0;
3808 else *cur = 0;
3809 ret = xmlMemStrdup(dir);
3810 } else {
3811 if (getcwd(dir, 1024) != NULL) {
3812 dir[1023] = 0;
3813 ret = xmlMemStrdup(dir);
3814 }
3815 }
3816 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003817#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003818}
3819
3820/****************************************************************
3821 * *
3822 * External entities loading *
3823 * *
3824 ****************************************************************/
3825
Daniel Veillarda840b692003-10-19 13:35:37 +00003826/**
3827 * xmlCheckHTTPInput:
3828 * @ctxt: an XML parser context
3829 * @ret: an XML parser input
3830 *
3831 * Check an input in case it was created from an HTTP stream, in that
3832 * case it will handle encoding and update of the base URL in case of
3833 * redirection. It also checks for HTTP errors in which case the input
3834 * is cleanly freed up and an appropriate error is raised in context
3835 *
3836 * Returns the input or NULL in case of HTTP error.
3837 */
3838xmlParserInputPtr
3839xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3840#ifdef LIBXML_HTTP_ENABLED
3841 if ((ret != NULL) && (ret->buf != NULL) &&
3842 (ret->buf->readcallback == xmlIOHTTPRead) &&
3843 (ret->buf->context != NULL)) {
3844 const char *encoding;
3845 const char *redir;
3846 const char *mime;
3847 int code;
3848
3849 code = xmlNanoHTTPReturnCode(ret->buf->context);
3850 if (code >= 400) {
3851 /* fatal error */
3852 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003853 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003854 (const char *) ret->filename);
3855 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003856 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003857 xmlFreeInputStream(ret);
3858 ret = NULL;
3859 } else {
3860
3861 mime = xmlNanoHTTPMimeType(ret->buf->context);
3862 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3863 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3864 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3865 if (encoding != NULL) {
3866 xmlCharEncodingHandlerPtr handler;
3867
3868 handler = xmlFindCharEncodingHandler(encoding);
3869 if (handler != NULL) {
3870 xmlSwitchInputEncoding(ctxt, ret, handler);
3871 } else {
3872 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3873 "Unknown encoding %s",
3874 BAD_CAST encoding, NULL);
3875 }
3876 if (ret->encoding == NULL)
3877 ret->encoding = xmlStrdup(BAD_CAST encoding);
3878 }
3879#if 0
3880 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3881#endif
3882 }
3883 redir = xmlNanoHTTPRedir(ret->buf->context);
3884 if (redir != NULL) {
3885 if (ret->filename != NULL)
3886 xmlFree((xmlChar *) ret->filename);
3887 if (ret->directory != NULL) {
3888 xmlFree((xmlChar *) ret->directory);
3889 ret->directory = NULL;
3890 }
3891 ret->filename =
3892 (char *) xmlStrdup((const xmlChar *) redir);
3893 }
3894 }
3895 }
3896#endif
3897 return(ret);
3898}
3899
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003900static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003901 const char *path;
3902
3903 if (URL == NULL)
3904 return(0);
3905
Daniel Veillardf4862f02002-09-10 11:13:43 +00003906 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003907#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003908 path = &URL[17];
3909#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003910 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003911#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003912 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003913#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003914 path = &URL[8];
3915#else
3916 path = &URL[7];
3917#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003918 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003919 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003920
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003921 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003922}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003923
Daniel Veillardad4e2962006-09-21 08:36:38 +00003924#ifdef LIBXML_CATALOG_ENABLED
3925
3926/**
3927 * xmlResolveResourceFromCatalog:
3928 * @URL: the URL for the entity to load
3929 * @ID: the System ID for the entity to load
3930 * @ctxt: the context in which the entity is called or NULL
3931 *
3932 * Resolves the URL and ID against the appropriate catalog.
3933 * This function is used by xmlDefaultExternalEntityLoader and
3934 * xmlNoNetExternalEntityLoader.
3935 *
3936 * Returns a new allocated URL, or NULL.
3937 */
William M. Brack38d452a2007-05-22 16:00:06 +00003938static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003939xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3940 xmlParserCtxtPtr ctxt) {
3941 xmlChar *resource = NULL;
3942 xmlCatalogAllow pref;
3943
3944 /*
3945 * If the resource doesn't exists as a file,
3946 * try to load it from the resource pointed in the catalogs
3947 */
3948 pref = xmlCatalogGetDefaults();
3949
3950 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3951 /*
3952 * Do a local lookup
3953 */
3954 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3955 ((pref == XML_CATA_ALLOW_ALL) ||
3956 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3957 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3958 (const xmlChar *)ID,
3959 (const xmlChar *)URL);
3960 }
3961 /*
3962 * Try a global lookup
3963 */
3964 if ((resource == NULL) &&
3965 ((pref == XML_CATA_ALLOW_ALL) ||
3966 (pref == XML_CATA_ALLOW_GLOBAL))) {
3967 resource = xmlCatalogResolve((const xmlChar *)ID,
3968 (const xmlChar *)URL);
3969 }
3970 if ((resource == NULL) && (URL != NULL))
3971 resource = xmlStrdup((const xmlChar *) URL);
3972
3973 /*
3974 * TODO: do an URI lookup on the reference
3975 */
3976 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3977 xmlChar *tmp = NULL;
3978
3979 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3980 ((pref == XML_CATA_ALLOW_ALL) ||
3981 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3982 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3983 }
3984 if ((tmp == NULL) &&
3985 ((pref == XML_CATA_ALLOW_ALL) ||
3986 (pref == XML_CATA_ALLOW_GLOBAL))) {
3987 tmp = xmlCatalogResolveURI(resource);
3988 }
3989
3990 if (tmp != NULL) {
3991 xmlFree(resource);
3992 resource = tmp;
3993 }
3994 }
3995 }
3996
3997 return resource;
3998}
3999
4000#endif
4001
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004002/**
Owen Taylor3473f882001-02-23 17:55:21 +00004003 * xmlDefaultExternalEntityLoader:
4004 * @URL: the URL for the entity to load
4005 * @ID: the System ID for the entity to load
4006 * @ctxt: the context in which the entity is called or NULL
4007 *
4008 * By default we don't load external entitites, yet.
4009 *
4010 * Returns a new allocated xmlParserInputPtr, or NULL.
4011 */
Daniel Veillarda840b692003-10-19 13:35:37 +00004012static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00004013xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00004014 xmlParserCtxtPtr ctxt)
4015{
Owen Taylor3473f882001-02-23 17:55:21 +00004016 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00004017 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00004018
Owen Taylor3473f882001-02-23 17:55:21 +00004019#ifdef DEBUG_EXTERNAL_ENTITIES
4020 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00004021 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004022#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00004023 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
4024 int options = ctxt->options;
4025
4026 ctxt->options -= XML_PARSE_NONET;
4027 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4028 ctxt->options = options;
4029 return(ret);
4030 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00004031#ifdef LIBXML_CATALOG_ENABLED
4032 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004033#endif
4034
4035 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004036 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004037
4038 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004039 if (ID == NULL)
4040 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004041 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004042 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004043 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004044 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004045 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004046 xmlFree(resource);
4047 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004048}
4049
4050static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4051 xmlDefaultExternalEntityLoader;
4052
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004053/**
Owen Taylor3473f882001-02-23 17:55:21 +00004054 * xmlSetExternalEntityLoader:
4055 * @f: the new entity resolver function
4056 *
4057 * Changes the defaultexternal entity resolver function for the application
4058 */
4059void
4060xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4061 xmlCurrentExternalEntityLoader = f;
4062}
4063
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004064/**
Owen Taylor3473f882001-02-23 17:55:21 +00004065 * xmlGetExternalEntityLoader:
4066 *
4067 * Get the default external entity resolver function for the application
4068 *
4069 * Returns the xmlExternalEntityLoader function pointer
4070 */
4071xmlExternalEntityLoader
4072xmlGetExternalEntityLoader(void) {
4073 return(xmlCurrentExternalEntityLoader);
4074}
4075
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004076/**
Owen Taylor3473f882001-02-23 17:55:21 +00004077 * xmlLoadExternalEntity:
4078 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004079 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004080 * @ctxt: the context in which the entity is called or NULL
4081 *
4082 * Load an external entity, note that the use of this function for
4083 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004084 *
4085 * Returns the xmlParserInputPtr or NULL
4086 */
4087xmlParserInputPtr
4088xmlLoadExternalEntity(const char *URL, const char *ID,
4089 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004090 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004091 char *canonicFilename;
4092 xmlParserInputPtr ret;
4093
4094 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4095 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004096 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004097 return(NULL);
4098 }
4099
4100 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4101 xmlFree(canonicFilename);
4102 return(ret);
4103 }
Owen Taylor3473f882001-02-23 17:55:21 +00004104 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4105}
4106
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004107/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004108 * *
4109 * Disabling Network access *
4110 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004111 ************************************************************************/
4112
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004113/**
4114 * xmlNoNetExternalEntityLoader:
4115 * @URL: the URL for the entity to load
4116 * @ID: the System ID for the entity to load
4117 * @ctxt: the context in which the entity is called or NULL
4118 *
4119 * A specific entity loader disabling network accesses, though still
4120 * allowing local catalog accesses for resolution.
4121 *
4122 * Returns a new allocated xmlParserInputPtr, or NULL.
4123 */
4124xmlParserInputPtr
4125xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4126 xmlParserCtxtPtr ctxt) {
4127 xmlParserInputPtr input = NULL;
4128 xmlChar *resource = NULL;
4129
4130#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004131 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004132#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004133
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004134 if (resource == NULL)
4135 resource = (xmlChar *) URL;
4136
4137 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004138 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4139 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004140 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004141 if (resource != (xmlChar *) URL)
4142 xmlFree(resource);
4143 return(NULL);
4144 }
4145 }
4146 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4147 if (resource != (xmlChar *) URL)
4148 xmlFree(resource);
4149 return(input);
4150}
4151
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004152#define bottom_xmlIO
4153#include "elfgcchack.h"