blob: c03ac430d6bd9521336776042285e6bd06f016de [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
38
Daniel Veillard59d3ed82007-04-17 12:44:58 +000039#if defined(WIN32) || defined(_WIN32)
Daniel Veillardf7416012006-04-27 08:15:20 +000040#include <windows.h>
41#endif
42
Daniel Veillard59d3ed82007-04-17 12:44:58 +000043#if defined(_WIN32_WCE)
44#include <winnls.h> /* for CP_UTF8 */
45#endif
46
Owen Taylor3473f882001-02-23 17:55:21 +000047/* Figure a portable way to know if a file is a directory. */
48#ifndef HAVE_STAT
49# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000050 /* MS C library seems to define stat and _stat. The definition
51 is identical. Still, mapping them to each other causes a warning. */
52# ifndef _MSC_VER
53# define stat(x,y) _stat(x,y)
54# endif
Owen Taylor3473f882001-02-23 17:55:21 +000055# define HAVE_STAT
56# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000057#else
58# ifdef HAVE__STAT
Daniel Veillard0da41662006-10-10 09:05:36 +000059# if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillard8ca85b22006-09-01 09:56:07 +000060# define stat _stat
Daniel Veillard0da41662006-10-10 09:05:36 +000061# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000062# endif
Owen Taylor3473f882001-02-23 17:55:21 +000063#endif
64#ifdef HAVE_STAT
65# ifndef S_ISDIR
66# ifdef _S_ISDIR
67# define S_ISDIR(x) _S_ISDIR(x)
68# else
69# ifdef S_IFDIR
70# ifndef S_IFMT
71# ifdef _S_IFMT
72# define S_IFMT _S_IFMT
73# endif
74# endif
75# ifdef S_IFMT
76# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
77# endif
78# endif
79# endif
80# endif
81#endif
82
83#include <libxml/xmlmemory.h>
84#include <libxml/parser.h>
85#include <libxml/parserInternals.h>
86#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000087#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000088#include <libxml/nanohttp.h>
89#include <libxml/nanoftp.h>
90#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000091#ifdef LIBXML_CATALOG_ENABLED
92#include <libxml/catalog.h>
93#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000094#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000095
Daniel Veillardf012a642001-07-23 19:10:52 +000096/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000097/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000098/* #define DEBUG_INPUT */
99
100#ifdef DEBUG_INPUT
101#define MINLEN 40
102#else
103#define MINLEN 4000
104#endif
105
106/*
107 * Input I/O callback sets
108 */
109typedef struct _xmlInputCallback {
110 xmlInputMatchCallback matchcallback;
111 xmlInputOpenCallback opencallback;
112 xmlInputReadCallback readcallback;
113 xmlInputCloseCallback closecallback;
114} xmlInputCallback;
115
116#define MAX_INPUT_CALLBACK 15
117
Daniel Veillard22090732001-07-16 00:06:07 +0000118static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
119static int xmlInputCallbackNr = 0;
120static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000121
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000122#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000123/*
124 * Output I/O callback sets
125 */
126typedef struct _xmlOutputCallback {
127 xmlOutputMatchCallback matchcallback;
128 xmlOutputOpenCallback opencallback;
129 xmlOutputWriteCallback writecallback;
130 xmlOutputCloseCallback closecallback;
131} xmlOutputCallback;
132
133#define MAX_OUTPUT_CALLBACK 15
134
Daniel Veillard22090732001-07-16 00:06:07 +0000135static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
136static int xmlOutputCallbackNr = 0;
137static int xmlOutputCallbackInitialized = 0;
Daniel Veillardda3fee42008-09-01 13:08:57 +0000138
139xmlOutputBufferPtr
140xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000141#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000142
Daniel Veillard05d987b2003-10-08 11:54:57 +0000143/************************************************************************
144 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200145 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000146 * *
147 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000148
Daniel Veillard05d987b2003-10-08 11:54:57 +0000149static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000150 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000151 "Permission denied", /* EACCES */
152 "Resource temporarily unavailable",/* EAGAIN */
153 "Bad file descriptor", /* EBADF */
154 "Bad message", /* EBADMSG */
155 "Resource busy", /* EBUSY */
156 "Operation canceled", /* ECANCELED */
157 "No child processes", /* ECHILD */
158 "Resource deadlock avoided",/* EDEADLK */
159 "Domain error", /* EDOM */
160 "File exists", /* EEXIST */
161 "Bad address", /* EFAULT */
162 "File too large", /* EFBIG */
163 "Operation in progress", /* EINPROGRESS */
164 "Interrupted function call",/* EINTR */
165 "Invalid argument", /* EINVAL */
166 "Input/output error", /* EIO */
167 "Is a directory", /* EISDIR */
168 "Too many open files", /* EMFILE */
169 "Too many links", /* EMLINK */
170 "Inappropriate message buffer length",/* EMSGSIZE */
171 "Filename too long", /* ENAMETOOLONG */
172 "Too many open files in system",/* ENFILE */
173 "No such device", /* ENODEV */
174 "No such file or directory",/* ENOENT */
175 "Exec format error", /* ENOEXEC */
176 "No locks available", /* ENOLCK */
177 "Not enough space", /* ENOMEM */
178 "No space left on device", /* ENOSPC */
179 "Function not implemented", /* ENOSYS */
180 "Not a directory", /* ENOTDIR */
181 "Directory not empty", /* ENOTEMPTY */
182 "Not supported", /* ENOTSUP */
183 "Inappropriate I/O control operation",/* ENOTTY */
184 "No such device or address",/* ENXIO */
185 "Operation not permitted", /* EPERM */
186 "Broken pipe", /* EPIPE */
187 "Result too large", /* ERANGE */
188 "Read-only file system", /* EROFS */
189 "Invalid seek", /* ESPIPE */
190 "No such process", /* ESRCH */
191 "Operation timed out", /* ETIMEDOUT */
192 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000193 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000194 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000195 "flush error",
196 "write error",
197 "no input",
198 "buffer full",
199 "loading error",
200 "not a socket", /* ENOTSOCK */
201 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000202 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000203 "unreachable network", /* ENETUNREACH */
204 "adddress in use", /* EADDRINUSE */
205 "already in use", /* EALREADY */
206 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000207};
208
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000209#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000210/**
211 * __xmlIOWin32UTF8ToWChar:
212 * @u8String: uft-8 string
213 *
214 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
215 */
216static wchar_t *
217__xmlIOWin32UTF8ToWChar(const char *u8String)
218{
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000219 wchar_t *wString = NULL;
Daniel Veillardf7416012006-04-27 08:15:20 +0000220
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000221 if (u8String) {
222 int wLen =
223 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
224 -1, NULL, 0);
225 if (wLen) {
226 wString = xmlMalloc(wLen * sizeof(wchar_t));
227 if (wString) {
228 if (MultiByteToWideChar
229 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
230 xmlFree(wString);
231 wString = NULL;
232 }
233 }
234 }
235 }
236
237 return wString;
Daniel Veillardf7416012006-04-27 08:15:20 +0000238}
239#endif
240
Daniel Veillard05d987b2003-10-08 11:54:57 +0000241/**
242 * xmlIOErrMemory:
243 * @extra: extra informations
244 *
245 * Handle an out of memory condition
246 */
247static void
248xmlIOErrMemory(const char *extra)
249{
250 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
251}
252
253/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000254 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000255 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000256 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000257 * @extra: extra informations
258 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000259 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000260 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000261void
262__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000263{
264 unsigned int idx;
265
266 if (code == 0) {
267#ifdef HAVE_ERRNO_H
268 if (errno == 0) code = 0;
269#ifdef EACCES
270 else if (errno == EACCES) code = XML_IO_EACCES;
271#endif
272#ifdef EAGAIN
273 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
274#endif
275#ifdef EBADF
276 else if (errno == EBADF) code = XML_IO_EBADF;
277#endif
278#ifdef EBADMSG
279 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
280#endif
281#ifdef EBUSY
282 else if (errno == EBUSY) code = XML_IO_EBUSY;
283#endif
284#ifdef ECANCELED
285 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
286#endif
287#ifdef ECHILD
288 else if (errno == ECHILD) code = XML_IO_ECHILD;
289#endif
290#ifdef EDEADLK
291 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
292#endif
293#ifdef EDOM
294 else if (errno == EDOM) code = XML_IO_EDOM;
295#endif
296#ifdef EEXIST
297 else if (errno == EEXIST) code = XML_IO_EEXIST;
298#endif
299#ifdef EFAULT
300 else if (errno == EFAULT) code = XML_IO_EFAULT;
301#endif
302#ifdef EFBIG
303 else if (errno == EFBIG) code = XML_IO_EFBIG;
304#endif
305#ifdef EINPROGRESS
306 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
307#endif
308#ifdef EINTR
309 else if (errno == EINTR) code = XML_IO_EINTR;
310#endif
311#ifdef EINVAL
312 else if (errno == EINVAL) code = XML_IO_EINVAL;
313#endif
314#ifdef EIO
315 else if (errno == EIO) code = XML_IO_EIO;
316#endif
317#ifdef EISDIR
318 else if (errno == EISDIR) code = XML_IO_EISDIR;
319#endif
320#ifdef EMFILE
321 else if (errno == EMFILE) code = XML_IO_EMFILE;
322#endif
323#ifdef EMLINK
324 else if (errno == EMLINK) code = XML_IO_EMLINK;
325#endif
326#ifdef EMSGSIZE
327 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
328#endif
329#ifdef ENAMETOOLONG
330 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
331#endif
332#ifdef ENFILE
333 else if (errno == ENFILE) code = XML_IO_ENFILE;
334#endif
335#ifdef ENODEV
336 else if (errno == ENODEV) code = XML_IO_ENODEV;
337#endif
338#ifdef ENOENT
339 else if (errno == ENOENT) code = XML_IO_ENOENT;
340#endif
341#ifdef ENOEXEC
342 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
343#endif
344#ifdef ENOLCK
345 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
346#endif
347#ifdef ENOMEM
348 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
349#endif
350#ifdef ENOSPC
351 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
352#endif
353#ifdef ENOSYS
354 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
355#endif
356#ifdef ENOTDIR
357 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
358#endif
359#ifdef ENOTEMPTY
360 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
361#endif
362#ifdef ENOTSUP
363 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
364#endif
365#ifdef ENOTTY
366 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
367#endif
368#ifdef ENXIO
369 else if (errno == ENXIO) code = XML_IO_ENXIO;
370#endif
371#ifdef EPERM
372 else if (errno == EPERM) code = XML_IO_EPERM;
373#endif
374#ifdef EPIPE
375 else if (errno == EPIPE) code = XML_IO_EPIPE;
376#endif
377#ifdef ERANGE
378 else if (errno == ERANGE) code = XML_IO_ERANGE;
379#endif
380#ifdef EROFS
381 else if (errno == EROFS) code = XML_IO_EROFS;
382#endif
383#ifdef ESPIPE
384 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
385#endif
386#ifdef ESRCH
387 else if (errno == ESRCH) code = XML_IO_ESRCH;
388#endif
389#ifdef ETIMEDOUT
390 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
391#endif
392#ifdef EXDEV
393 else if (errno == EXDEV) code = XML_IO_EXDEV;
394#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000395#ifdef ENOTSOCK
396 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
397#endif
398#ifdef EISCONN
399 else if (errno == EISCONN) code = XML_IO_EISCONN;
400#endif
401#ifdef ECONNREFUSED
402 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
403#endif
404#ifdef ETIMEDOUT
405 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
406#endif
407#ifdef ENETUNREACH
408 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
409#endif
410#ifdef EADDRINUSE
411 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
412#endif
413#ifdef EINPROGRESS
414 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
415#endif
416#ifdef EALREADY
417 else if (errno == EALREADY) code = XML_IO_EALREADY;
418#endif
419#ifdef EAFNOSUPPORT
420 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
421#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000422 else code = XML_IO_UNKNOWN;
423#endif /* HAVE_ERRNO_H */
424 }
425 idx = 0;
426 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
427 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200428
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000429 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
430}
431
432/**
433 * xmlIOErr:
434 * @code: the error number
435 * @extra: extra informations
436 *
437 * Handle an I/O error
438 */
439static void
440xmlIOErr(int code, const char *extra)
441{
442 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000443}
444
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000445/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000446 * __xmlLoaderErr:
447 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000448 * @extra: extra informations
449 *
450 * Handle a resource access error
451 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000452void
453__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000454{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000455 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000456 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000457 xmlGenericErrorFunc channel = NULL;
458 void *data = NULL;
459 xmlErrorLevel level = XML_ERR_ERROR;
460
Daniel Veillard157fee02003-10-31 10:36:03 +0000461 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
462 (ctxt->instate == XML_PARSER_EOF))
463 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000464 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
465 if (ctxt->validate) {
466 channel = ctxt->sax->error;
467 level = XML_ERR_ERROR;
468 } else {
469 channel = ctxt->sax->warning;
470 level = XML_ERR_WARNING;
471 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000472 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
473 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000474 data = ctxt->userData;
475 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000476 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000477 XML_IO_LOAD_ERROR, level, NULL, 0,
478 filename, NULL, NULL, 0, 0,
479 msg, filename);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200480
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000481}
482
Daniel Veillard05d987b2003-10-08 11:54:57 +0000483/************************************************************************
484 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200485 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000486 * *
487 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000488/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000489 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000490 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000491 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000492 * This function is obsolete. Please see xmlURIFromPath in uri.c for
493 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000494 *
495 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000496 */
497xmlChar *
498xmlNormalizeWindowsPath(const xmlChar *path)
499{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000500 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000501}
502
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000503/**
504 * xmlCleanupInputCallbacks:
505 *
506 * clears the entire input callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200507 * compiled-in I/O.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000508 */
509void
510xmlCleanupInputCallbacks(void)
511{
512 int i;
513
514 if (!xmlInputCallbackInitialized)
515 return;
516
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000517 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000518 xmlInputCallbackTable[i].matchcallback = NULL;
519 xmlInputCallbackTable[i].opencallback = NULL;
520 xmlInputCallbackTable[i].readcallback = NULL;
521 xmlInputCallbackTable[i].closecallback = NULL;
522 }
523
524 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000525 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000526}
527
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000528/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000529 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000530 *
531 * Clear the top input callback from the input stack. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200532 * compiled-in I/O.
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000533 *
534 * Returns the number of input callback registered or -1 in case of error.
535 */
536int
537xmlPopInputCallbacks(void)
538{
539 if (!xmlInputCallbackInitialized)
540 return(-1);
541
542 if (xmlInputCallbackNr <= 0)
543 return(-1);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200544
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000545 xmlInputCallbackNr--;
546 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
547 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
548 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
549 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
550
551 return(xmlInputCallbackNr);
552}
553
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000554#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000555/**
556 * xmlCleanupOutputCallbacks:
557 *
558 * clears the entire output callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200559 * compiled-in I/O callbacks.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000560 */
561void
562xmlCleanupOutputCallbacks(void)
563{
564 int i;
565
566 if (!xmlOutputCallbackInitialized)
567 return;
568
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000569 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000570 xmlOutputCallbackTable[i].matchcallback = NULL;
571 xmlOutputCallbackTable[i].opencallback = NULL;
572 xmlOutputCallbackTable[i].writecallback = NULL;
573 xmlOutputCallbackTable[i].closecallback = NULL;
574 }
575
576 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000577 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000578}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000579#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000580
Owen Taylor3473f882001-02-23 17:55:21 +0000581/************************************************************************
582 * *
583 * Standard I/O for file accesses *
584 * *
585 ************************************************************************/
586
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000587#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
588
589/**
590 * xmlWrapOpenUtf8:
591 * @path: the path in utf-8 encoding
592 * @mode: type of access (0 - read, 1 - write)
593 *
594 * function opens the file specified by @path
595 *
596 */
597static FILE*
598xmlWrapOpenUtf8(const char *path,int mode)
599{
600 FILE *fd = NULL;
601 wchar_t *wPath;
602
603 wPath = __xmlIOWin32UTF8ToWChar(path);
604 if(wPath)
605 {
606 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
607 xmlFree(wPath);
608 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000609 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000610 if(fd == NULL)
611 fd = fopen(path, mode ? "wb" : "rb");
612
613 return fd;
614}
615
Rob Richards6c61e022009-08-12 11:41:27 -0400616#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200617static gzFile
618xmlWrapGzOpenUtf8(const char *path, const char *mode)
619{
620 gzFile fd;
621 wchar_t *wPath;
622
623 fd = gzopen (path, mode);
624 if (fd)
625 return fd;
626
627 wPath = __xmlIOWin32UTF8ToWChar(path);
628 if(wPath)
629 {
630 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
631#ifdef _O_BINARY
632 m |= (strstr(mode, "b") ? _O_BINARY : 0);
633#endif
634 d = _wopen(wPath, m);
635 if (d >= 0)
636 fd = gzdopen(d, mode);
637 xmlFree(wPath);
638 }
639
640 return fd;
641}
Rob Richards6c61e022009-08-12 11:41:27 -0400642#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200643
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000644/**
645 * xmlWrapStatUtf8:
646 * @path: the path in utf-8 encoding
647 * @info: structure that stores results
648 *
649 * function obtains information about the file or directory
650 *
651 */
652static int
653xmlWrapStatUtf8(const char *path,struct stat *info)
654{
655#ifdef HAVE_STAT
656 int retval = -1;
657 wchar_t *wPath;
658
659 wPath = __xmlIOWin32UTF8ToWChar(path);
660 if (wPath)
661 {
662 retval = _wstat(wPath,info);
663 xmlFree(wPath);
664 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000665 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000666 if(retval < 0)
667 retval = stat(path,info);
668 return retval;
669#else
670 return -1;
671#endif
672}
673
674/**
675 * xmlWrapOpenNative:
676 * @path: the path
677 * @mode: type of access (0 - read, 1 - write)
678 *
679 * function opens the file specified by @path
680 *
681 */
682static FILE*
683xmlWrapOpenNative(const char *path,int mode)
684{
685 return fopen(path,mode ? "wb" : "rb");
686}
687
688/**
689 * xmlWrapStatNative:
690 * @path: the path
691 * @info: structure that stores results
692 *
693 * function obtains information about the file or directory
694 *
695 */
696static int
697xmlWrapStatNative(const char *path,struct stat *info)
698{
699#ifdef HAVE_STAT
700 return stat(path,info);
701#else
702 return -1;
703#endif
704}
705
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000706typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
707static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
708typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
Rob Richards6460f922006-10-12 21:08:29 +0000709static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400710#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200711typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
712static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400713#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000714/**
715 * xmlInitPlatformSpecificIo:
716 *
717 * Initialize platform specific features.
718 */
719static void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000720xmlInitPlatformSpecificIo(void)
721{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000722 static int xmlPlatformIoInitialized = 0;
723 OSVERSIONINFO osvi;
724
725 if(xmlPlatformIoInitialized)
726 return;
727
728 osvi.dwOSVersionInfoSize = sizeof(osvi);
729
730 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
731 xmlWrapStat = xmlWrapStatUtf8;
732 xmlWrapOpen = xmlWrapOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400733#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200734 xmlWrapGzOpen = xmlWrapGzOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400735#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000736 } else {
737 xmlWrapStat = xmlWrapStatNative;
738 xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400739#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200740 xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400741#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000742 }
743
744 xmlPlatformIoInitialized = 1;
745 return;
746}
747
748#endif
749
Owen Taylor3473f882001-02-23 17:55:21 +0000750/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000751 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000752 * @path: the path to check
753 *
754 * function checks to see if @path is a valid source
755 * (file, socket...) for XML.
756 *
757 * if stat is not available on the target machine,
758 * returns 1. if stat fails, returns 0 (if calling
759 * stat on the filename fails, it can't be right).
760 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000761 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000762 */
763
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000764int
Owen Taylor3473f882001-02-23 17:55:21 +0000765xmlCheckFilename (const char *path)
766{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000767#ifdef HAVE_STAT
Daniel Veillard0b309952006-05-02 20:34:38 +0000768 struct stat stat_buffer;
769#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000770 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000771 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000772
Owen Taylor3473f882001-02-23 17:55:21 +0000773#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000774#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
775 if (xmlWrapStat(path, &stat_buffer) == -1)
776 return 0;
777#else
Owen Taylor3473f882001-02-23 17:55:21 +0000778 if (stat(path, &stat_buffer) == -1)
779 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000780#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000781#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000782 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000783 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000784#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000785#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000786 return 1;
787}
788
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000789static int
Owen Taylor3473f882001-02-23 17:55:21 +0000790xmlNop(void) {
791 return(0);
792}
793
794/**
Owen Taylor3473f882001-02-23 17:55:21 +0000795 * xmlFdRead:
796 * @context: the I/O context
797 * @buffer: where to drop data
798 * @len: number of bytes to read
799 *
800 * Read @len bytes to @buffer from the I/O channel.
801 *
802 * Returns the number of bytes written
803 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000804static int
Owen Taylor3473f882001-02-23 17:55:21 +0000805xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000806 int ret;
807
808 ret = read((int) (long) context, &buffer[0], len);
809 if (ret < 0) xmlIOErr(0, "read()");
810 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000811}
812
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000813#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000814/**
815 * xmlFdWrite:
816 * @context: the I/O context
817 * @buffer: where to get data
818 * @len: number of bytes to write
819 *
820 * Write @len bytes from @buffer to the I/O channel.
821 *
822 * Returns the number of bytes written
823 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000824static int
Owen Taylor3473f882001-02-23 17:55:21 +0000825xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000826 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000827
Daniel Veillard9b693b42005-10-28 14:54:17 +0000828 if (len > 0) {
829 ret = write((int) (long) context, &buffer[0], len);
830 if (ret < 0) xmlIOErr(0, "write()");
831 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000832 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000833}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000834#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000835
836/**
837 * xmlFdClose:
838 * @context: the I/O context
839 *
840 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000841 *
842 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000843 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000844static int
Owen Taylor3473f882001-02-23 17:55:21 +0000845xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000846 int ret;
847 ret = close((int) (long) context);
848 if (ret < 0) xmlIOErr(0, "close()");
849 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000850}
851
852/**
853 * xmlFileMatch:
854 * @filename: the URI for matching
855 *
856 * input from FILE *
857 *
858 * Returns 1 if matches, 0 otherwise
859 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000860int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000861xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000862 return(1);
863}
864
865/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000866 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000867 * @filename: the URI for matching
868 *
869 * input from FILE *, supports compressed input
870 * if @filename is " " then the standard input is used
871 *
872 * Returns an I/O context or NULL in case of error
873 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000874static void *
875xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000876 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000877 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000878
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000879 if (filename == NULL)
880 return(NULL);
881
Owen Taylor3473f882001-02-23 17:55:21 +0000882 if (!strcmp(filename, "-")) {
883 fd = stdin;
884 return((void *) fd);
885 }
886
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000887 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000888#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000889 path = &filename[17];
890#else
Owen Taylor3473f882001-02-23 17:55:21 +0000891 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000892#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000893 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000894#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000895 path = &filename[8];
896#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000897 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000898#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000899 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
900 /* lots of generators seems to lazy to read RFC 1738 */
901#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
902 path = &filename[6];
903#else
904 path = &filename[5];
905#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200906 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000907 path = filename;
908
909 if (path == NULL)
910 return(NULL);
911 if (!xmlCheckFilename(path))
912 return(NULL);
913
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000914#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
915 fd = xmlWrapOpen(path, 0);
916#else
917 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000918#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000919 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000920 return((void *) fd);
921}
922
923/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000924 * xmlFileOpen:
925 * @filename: the URI for matching
926 *
927 * Wrapper around xmlFileOpen_real that try it with an unescaped
928 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000929 *
930 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000931 */
932void *
933xmlFileOpen (const char *filename) {
934 char *unescaped;
935 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000936
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000937 retval = xmlFileOpen_real(filename);
938 if (retval == NULL) {
939 unescaped = xmlURIUnescapeString(filename, 0, NULL);
940 if (unescaped != NULL) {
941 retval = xmlFileOpen_real(unescaped);
942 xmlFree(unescaped);
943 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000944 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000945
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000946 return retval;
947}
948
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000949#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000950/**
Owen Taylor3473f882001-02-23 17:55:21 +0000951 * xmlFileOpenW:
952 * @filename: the URI for matching
953 *
954 * output to from FILE *,
955 * if @filename is "-" then the standard output is used
956 *
957 * Returns an I/O context or NULL in case of error
958 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000959static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000960xmlFileOpenW (const char *filename) {
961 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000962 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000963
964 if (!strcmp(filename, "-")) {
965 fd = stdout;
966 return((void *) fd);
967 }
968
Daniel Veillardf4862f02002-09-10 11:13:43 +0000969 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000970#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000971 path = &filename[17];
972#else
Owen Taylor3473f882001-02-23 17:55:21 +0000973 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000974#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000975 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000976#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000977 path = &filename[8];
978#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000979 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000980#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200981 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000982 path = filename;
983
984 if (path == NULL)
985 return(NULL);
986
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000987#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
988 fd = xmlWrapOpen(path, 1);
989#else
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200990 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000991#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000992
Daniel Veillardf7416012006-04-27 08:15:20 +0000993 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000994 return((void *) fd);
995}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000996#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000997
998/**
999 * xmlFileRead:
1000 * @context: the I/O context
1001 * @buffer: where to drop data
1002 * @len: number of bytes to write
1003 *
1004 * Read @len bytes to @buffer from the I/O channel.
1005 *
Daniel Veillardce682bc2004-11-05 17:22:25 +00001006 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001007 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001008int
Owen Taylor3473f882001-02-23 17:55:21 +00001009xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001010 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001011 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001012 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001013 ret = fread(&buffer[0], 1, len, (FILE *) context);
1014 if (ret < 0) xmlIOErr(0, "fread()");
1015 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001016}
1017
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001018#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001019/**
1020 * xmlFileWrite:
1021 * @context: the I/O context
1022 * @buffer: where to drop data
1023 * @len: number of bytes to write
1024 *
1025 * Write @len bytes from @buffer to the I/O channel.
1026 *
1027 * Returns the number of bytes written
1028 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001029static int
Owen Taylor3473f882001-02-23 17:55:21 +00001030xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001031 int items;
1032
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001033 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001034 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001035 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001036 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001037 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001038 return(-1);
1039 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001040 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001041}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001042#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001043
1044/**
1045 * xmlFileClose:
1046 * @context: the I/O context
1047 *
1048 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001049 *
1050 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001051 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001052int
Owen Taylor3473f882001-02-23 17:55:21 +00001053xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001054 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001055 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001056
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001057 if (context == NULL)
1058 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001059 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001060 if ((fil == stdout) || (fil == stderr)) {
1061 ret = fflush(fil);
1062 if (ret < 0)
1063 xmlIOErr(0, "fflush()");
1064 return(0);
1065 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001066 if (fil == stdin)
1067 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001068 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1069 if (ret < 0)
1070 xmlIOErr(0, "fclose()");
1071 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001072}
1073
1074/**
1075 * xmlFileFlush:
1076 * @context: the I/O context
1077 *
1078 * Flush an I/O channel
1079 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001080static int
Owen Taylor3473f882001-02-23 17:55:21 +00001081xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001082 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001083
1084 if (context == NULL)
1085 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001086 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1087 if (ret < 0)
1088 xmlIOErr(0, "fflush()");
1089 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001090}
1091
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001092#ifdef LIBXML_OUTPUT_ENABLED
1093/**
1094 * xmlBufferWrite:
1095 * @context: the xmlBuffer
1096 * @buffer: the data to write
1097 * @len: number of bytes to write
1098 *
1099 * Write @len bytes from @buffer to the xml buffer
1100 *
1101 * Returns the number of bytes written
1102 */
1103static int
1104xmlBufferWrite (void * context, const char * buffer, int len) {
1105 int ret;
1106
1107 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1108 if (ret != 0)
1109 return(-1);
1110 return(len);
1111}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001112#endif
1113
Owen Taylor3473f882001-02-23 17:55:21 +00001114#ifdef HAVE_ZLIB_H
1115/************************************************************************
1116 * *
1117 * I/O for compressed file accesses *
1118 * *
1119 ************************************************************************/
1120/**
1121 * xmlGzfileMatch:
1122 * @filename: the URI for matching
1123 *
1124 * input from compressed file test
1125 *
1126 * Returns 1 if matches, 0 otherwise
1127 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001128static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001129xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001130 return(1);
1131}
1132
1133/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001134 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001135 * @filename: the URI for matching
1136 *
1137 * input from compressed file open
1138 * if @filename is " " then the standard input is used
1139 *
1140 * Returns an I/O context or NULL in case of error
1141 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001142static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001143xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001144 const char *path = NULL;
1145 gzFile fd;
1146
1147 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001148 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001149 return((void *) fd);
1150 }
1151
Daniel Veillardf4862f02002-09-10 11:13:43 +00001152 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001153#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001154 path = &filename[17];
1155#else
Owen Taylor3473f882001-02-23 17:55:21 +00001156 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001157#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001158 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001159#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001160 path = &filename[8];
1161#else
Owen Taylor3473f882001-02-23 17:55:21 +00001162 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001163#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001164 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001165 path = filename;
1166
1167 if (path == NULL)
1168 return(NULL);
1169 if (!xmlCheckFilename(path))
1170 return(NULL);
1171
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001172#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1173 fd = xmlWrapGzOpen(path, "rb");
1174#else
Owen Taylor3473f882001-02-23 17:55:21 +00001175 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001176#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001177 return((void *) fd);
1178}
1179
1180/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001181 * xmlGzfileOpen:
1182 * @filename: the URI for matching
1183 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001184 * Wrapper around xmlGzfileOpen if the open fais, it will
1185 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001186 */
1187static void *
1188xmlGzfileOpen (const char *filename) {
1189 char *unescaped;
1190 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001191
1192 retval = xmlGzfileOpen_real(filename);
1193 if (retval == NULL) {
1194 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1195 if (unescaped != NULL) {
1196 retval = xmlGzfileOpen_real(unescaped);
1197 }
1198 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001199 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001200 return retval;
1201}
1202
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001203#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001204/**
Owen Taylor3473f882001-02-23 17:55:21 +00001205 * xmlGzfileOpenW:
1206 * @filename: the URI for matching
1207 * @compression: the compression factor (0 - 9 included)
1208 *
1209 * input from compressed file open
1210 * if @filename is " " then the standard input is used
1211 *
1212 * Returns an I/O context or NULL in case of error
1213 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001214static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001215xmlGzfileOpenW (const char *filename, int compression) {
1216 const char *path = NULL;
1217 char mode[15];
1218 gzFile fd;
1219
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001220 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001221 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001222 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001223 return((void *) fd);
1224 }
1225
Daniel Veillardf4862f02002-09-10 11:13:43 +00001226 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001227#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001228 path = &filename[17];
1229#else
Owen Taylor3473f882001-02-23 17:55:21 +00001230 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001231#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001232 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001233#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001234 path = &filename[8];
1235#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001236 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001237#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001238 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001239 path = filename;
1240
1241 if (path == NULL)
1242 return(NULL);
1243
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001244#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1245 fd = xmlWrapGzOpen(path, mode);
1246#else
Owen Taylor3473f882001-02-23 17:55:21 +00001247 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001248#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001249 return((void *) fd);
1250}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001251#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001252
1253/**
1254 * xmlGzfileRead:
1255 * @context: the I/O context
1256 * @buffer: where to drop data
1257 * @len: number of bytes to write
1258 *
1259 * Read @len bytes to @buffer from the compressed I/O channel.
1260 *
1261 * Returns the number of bytes written
1262 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001263static int
Owen Taylor3473f882001-02-23 17:55:21 +00001264xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001265 int ret;
1266
1267 ret = gzread((gzFile) context, &buffer[0], len);
1268 if (ret < 0) xmlIOErr(0, "gzread()");
1269 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001270}
1271
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001272#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001273/**
1274 * xmlGzfileWrite:
1275 * @context: the I/O context
1276 * @buffer: where to drop data
1277 * @len: number of bytes to write
1278 *
1279 * Write @len bytes from @buffer to the compressed I/O channel.
1280 *
1281 * Returns the number of bytes written
1282 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001283static int
Owen Taylor3473f882001-02-23 17:55:21 +00001284xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001285 int ret;
1286
1287 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1288 if (ret < 0) xmlIOErr(0, "gzwrite()");
1289 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001290}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001291#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001292
1293/**
1294 * xmlGzfileClose:
1295 * @context: the I/O context
1296 *
1297 * Close a compressed I/O channel
1298 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001299static int
Owen Taylor3473f882001-02-23 17:55:21 +00001300xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001301 int ret;
1302
1303 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1304 if (ret < 0) xmlIOErr(0, "gzclose()");
1305 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001306}
1307#endif /* HAVE_ZLIB_H */
1308
1309#ifdef LIBXML_HTTP_ENABLED
1310/************************************************************************
1311 * *
1312 * I/O for HTTP file accesses *
1313 * *
1314 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001315
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001316#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001317typedef struct xmlIOHTTPWriteCtxt_
1318{
1319 int compression;
1320
1321 char * uri;
1322
1323 void * doc_buff;
1324
1325} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1326
1327#ifdef HAVE_ZLIB_H
1328
1329#define DFLT_WBITS ( -15 )
1330#define DFLT_MEM_LVL ( 8 )
1331#define GZ_MAGIC1 ( 0x1f )
1332#define GZ_MAGIC2 ( 0x8b )
1333#define LXML_ZLIB_OS_CODE ( 0x03 )
1334#define INIT_HTTP_BUFF_SIZE ( 32768 )
1335#define DFLT_ZLIB_RATIO ( 5 )
1336
1337/*
1338** Data structure and functions to work with sending compressed data
1339** via HTTP.
1340*/
1341
1342typedef struct xmlZMemBuff_
1343{
1344 unsigned long size;
1345 unsigned long crc;
1346
1347 unsigned char * zbuff;
1348 z_stream zctrl;
1349
1350} xmlZMemBuff, *xmlZMemBuffPtr;
1351
1352/**
1353 * append_reverse_ulong
1354 * @buff: Compressed memory buffer
1355 * @data: Unsigned long to append
1356 *
1357 * Append a unsigned long in reverse byte order to the end of the
1358 * memory buffer.
1359 */
1360static void
1361append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1362
1363 int idx;
1364
1365 if ( buff == NULL )
1366 return;
1367
1368 /*
1369 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001370 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001371 ** support 64 bit file sizes, this code would need to be patched
1372 ** as well.
1373 */
1374
1375 for ( idx = 0; idx < 4; idx++ ) {
1376 *buff->zctrl.next_out = ( data & 0xff );
1377 data >>= 8;
1378 buff->zctrl.next_out++;
1379 }
1380
1381 return;
1382}
1383
1384/**
1385 *
1386 * xmlFreeZMemBuff
1387 * @buff: The memory buffer context to clear
1388 *
1389 * Release all the resources associated with the compressed memory buffer.
1390 */
1391static void
1392xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001393
1394#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001395 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001396#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001397
1398 if ( buff == NULL )
1399 return;
1400
1401 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001402#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001403 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001404 if ( z_err != Z_OK )
1405 xmlGenericError( xmlGenericErrorContext,
1406 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1407 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001408#else
1409 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001410#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001411
1412 xmlFree( buff );
1413 return;
1414}
1415
1416/**
1417 * xmlCreateZMemBuff
1418 *@compression: Compression value to use
1419 *
1420 * Create a memory buffer to hold the compressed XML document. The
1421 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001422 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001423 * write the document to disk. The code for the header/trailer data to
1424 * the compression is plagiarized from the zlib source files.
1425 */
1426static void *
1427xmlCreateZMemBuff( int compression ) {
1428
1429 int z_err;
1430 int hdr_lgth;
1431 xmlZMemBuffPtr buff = NULL;
1432
1433 if ( ( compression < 1 ) || ( compression > 9 ) )
1434 return ( NULL );
1435
1436 /* Create the control and data areas */
1437
1438 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1439 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001440 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001441 return ( NULL );
1442 }
1443
1444 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1445 buff->size = INIT_HTTP_BUFF_SIZE;
1446 buff->zbuff = xmlMalloc( buff->size );
1447 if ( buff->zbuff == NULL ) {
1448 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001449 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001450 return ( NULL );
1451 }
1452
1453 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1454 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1455 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001456 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001457 xmlFreeZMemBuff( buff );
1458 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001459 xmlStrPrintf(msg, 500,
1460 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1461 "Error initializing compression context. ZLIB error:",
1462 z_err );
1463 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001464 return ( NULL );
1465 }
1466
1467 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001468 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001469 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1470 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001471 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001472 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1473 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1474 buff->zctrl.avail_out = buff->size - hdr_lgth;
1475
1476 return ( buff );
1477}
1478
1479/**
1480 * xmlZMemBuffExtend
1481 * @buff: Buffer used to compress and consolidate data.
1482 * @ext_amt: Number of bytes to extend the buffer.
1483 *
1484 * Extend the internal buffer used to store the compressed data by the
1485 * specified amount.
1486 *
1487 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1488 * the original buffer still exists at the original size.
1489 */
1490static int
1491xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1492
1493 int rc = -1;
1494 size_t new_size;
1495 size_t cur_used;
1496
1497 unsigned char * tmp_ptr = NULL;
1498
1499 if ( buff == NULL )
1500 return ( -1 );
1501
1502 else if ( ext_amt == 0 )
1503 return ( 0 );
1504
1505 cur_used = buff->zctrl.next_out - buff->zbuff;
1506 new_size = buff->size + ext_amt;
1507
1508#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001509 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001510 xmlGenericError( xmlGenericErrorContext,
1511 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1512 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001513 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001514 (cur_used - new_size ) );
1515#endif
1516
1517 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1518 if ( tmp_ptr != NULL ) {
1519 rc = 0;
1520 buff->size = new_size;
1521 buff->zbuff = tmp_ptr;
1522 buff->zctrl.next_out = tmp_ptr + cur_used;
1523 buff->zctrl.avail_out = new_size - cur_used;
1524 }
1525 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001526 xmlChar msg[500];
1527 xmlStrPrintf(msg, 500,
1528 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1529 "Allocation failure extending output buffer to",
1530 new_size );
1531 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001532 }
1533
1534 return ( rc );
1535}
1536
1537/**
1538 * xmlZMemBuffAppend
1539 * @buff: Buffer used to compress and consolidate data
1540 * @src: Uncompressed source content to append to buffer
1541 * @len: Length of source data to append to buffer
1542 *
1543 * Compress and append data to the internal buffer. The data buffer
1544 * will be expanded if needed to store the additional data.
1545 *
1546 * Returns the number of bytes appended to the buffer or -1 on error.
1547 */
1548static int
1549xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1550
1551 int z_err;
1552 size_t min_accept;
1553
1554 if ( ( buff == NULL ) || ( src == NULL ) )
1555 return ( -1 );
1556
1557 buff->zctrl.avail_in = len;
1558 buff->zctrl.next_in = (unsigned char *)src;
1559 while ( buff->zctrl.avail_in > 0 ) {
1560 /*
1561 ** Extend the buffer prior to deflate call if a reasonable amount
1562 ** of output buffer space is not available.
1563 */
1564 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1565 if ( buff->zctrl.avail_out <= min_accept ) {
1566 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1567 return ( -1 );
1568 }
1569
1570 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1571 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001572 xmlChar msg[500];
1573 xmlStrPrintf(msg, 500,
1574 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001575 "Compression error while appending",
1576 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001577 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001578 return ( -1 );
1579 }
1580 }
1581
1582 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1583
1584 return ( len );
1585}
1586
1587/**
1588 * xmlZMemBuffGetContent
1589 * @buff: Compressed memory content buffer
1590 * @data_ref: Pointer reference to point to compressed content
1591 *
1592 * Flushes the compression buffers, appends gzip file trailers and
1593 * returns the compressed content and length of the compressed data.
1594 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1595 *
1596 * Returns the length of the compressed data or -1 on error.
1597 */
1598static int
1599xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1600
1601 int zlgth = -1;
1602 int z_err;
1603
1604 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1605 return ( -1 );
1606
1607 /* Need to loop until compression output buffers are flushed */
1608
1609 do
1610 {
1611 z_err = deflate( &buff->zctrl, Z_FINISH );
1612 if ( z_err == Z_OK ) {
1613 /* In this case Z_OK means more buffer space needed */
1614
1615 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1616 return ( -1 );
1617 }
1618 }
1619 while ( z_err == Z_OK );
1620
1621 /* If the compression state is not Z_STREAM_END, some error occurred */
1622
1623 if ( z_err == Z_STREAM_END ) {
1624
1625 /* Need to append the gzip data trailer */
1626
1627 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1628 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1629 return ( -1 );
1630 }
1631
1632 /*
1633 ** For whatever reason, the CRC and length data are pushed out
1634 ** in reverse byte order. So a memcpy can't be used here.
1635 */
1636
1637 append_reverse_ulong( buff, buff->crc );
1638 append_reverse_ulong( buff, buff->zctrl.total_in );
1639
1640 zlgth = buff->zctrl.next_out - buff->zbuff;
1641 *data_ref = (char *)buff->zbuff;
1642 }
1643
Daniel Veillard05d987b2003-10-08 11:54:57 +00001644 else {
1645 xmlChar msg[500];
1646 xmlStrPrintf(msg, 500,
1647 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1648 "Error flushing zlib buffers. Error code", z_err );
1649 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1650 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001651
Daniel Veillardf012a642001-07-23 19:10:52 +00001652 return ( zlgth );
1653}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001654#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001655#endif /* HAVE_ZLIB_H */
1656
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001657#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001658/**
1659 * xmlFreeHTTPWriteCtxt
1660 * @ctxt: Context to cleanup
1661 *
1662 * Free allocated memory and reclaim system resources.
1663 *
1664 * No return value.
1665 */
1666static void
1667xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1668{
1669 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001670 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001671
1672 if ( ctxt->doc_buff != NULL ) {
1673
1674#ifdef HAVE_ZLIB_H
1675 if ( ctxt->compression > 0 ) {
1676 xmlFreeZMemBuff( ctxt->doc_buff );
1677 }
1678 else
1679#endif
1680 {
1681 xmlOutputBufferClose( ctxt->doc_buff );
1682 }
1683 }
1684
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001685 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001686 return;
1687}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001688#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001689
1690
Owen Taylor3473f882001-02-23 17:55:21 +00001691/**
1692 * xmlIOHTTPMatch:
1693 * @filename: the URI for matching
1694 *
1695 * check if the URI matches an HTTP one
1696 *
1697 * Returns 1 if matches, 0 otherwise
1698 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001699int
Owen Taylor3473f882001-02-23 17:55:21 +00001700xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001701 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001702 return(1);
1703 return(0);
1704}
1705
1706/**
1707 * xmlIOHTTPOpen:
1708 * @filename: the URI for matching
1709 *
1710 * open an HTTP I/O channel
1711 *
1712 * Returns an I/O context or NULL in case of error
1713 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001714void *
Owen Taylor3473f882001-02-23 17:55:21 +00001715xmlIOHTTPOpen (const char *filename) {
1716 return(xmlNanoHTTPOpen(filename, NULL));
1717}
1718
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001719#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001720/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001721 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001722 * @post_uri: The destination URI for the document
1723 * @compression: The compression desired for the document.
1724 *
1725 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1726 * request. Non-static as is called from the output buffer creation routine.
1727 *
1728 * Returns an I/O context or NULL in case of error.
1729 */
1730
1731void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001732xmlIOHTTPOpenW(const char *post_uri, int compression)
1733{
Daniel Veillardf012a642001-07-23 19:10:52 +00001734
Daniel Veillard572577e2002-01-18 16:23:55 +00001735 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001736
Daniel Veillard572577e2002-01-18 16:23:55 +00001737 if (post_uri == NULL)
1738 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001739
Daniel Veillard572577e2002-01-18 16:23:55 +00001740 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1741 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001742 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001743 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001744 }
1745
Daniel Veillard572577e2002-01-18 16:23:55 +00001746 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001747
Daniel Veillard572577e2002-01-18 16:23:55 +00001748 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1749 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001750 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001751 xmlFreeHTTPWriteCtxt(ctxt);
1752 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001753 }
1754
1755 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001756 * ** Since the document length is required for an HTTP post,
1757 * ** need to put the document into a buffer. A memory buffer
1758 * ** is being used to avoid pushing the data to disk and back.
1759 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001760
1761#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001762 if ((compression > 0) && (compression <= 9)) {
1763
1764 ctxt->compression = compression;
1765 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1766 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001767#endif
1768 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001769 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001770
Daniel Veillardda3fee42008-09-01 13:08:57 +00001771 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001772 }
1773
Daniel Veillard572577e2002-01-18 16:23:55 +00001774 if (ctxt->doc_buff == NULL) {
1775 xmlFreeHTTPWriteCtxt(ctxt);
1776 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001777 }
1778
Daniel Veillard572577e2002-01-18 16:23:55 +00001779 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001780}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001781#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001782
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001783#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001784/**
1785 * xmlIOHTTPDfltOpenW
1786 * @post_uri: The destination URI for this document.
1787 *
1788 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1789 * HTTP post command. This function should generally not be used as
1790 * the open callback is short circuited in xmlOutputBufferCreateFile.
1791 *
1792 * Returns a pointer to the new IO context.
1793 */
1794static void *
1795xmlIOHTTPDfltOpenW( const char * post_uri ) {
1796 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1797}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001798#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001799
1800/**
Owen Taylor3473f882001-02-23 17:55:21 +00001801 * xmlIOHTTPRead:
1802 * @context: the I/O context
1803 * @buffer: where to drop data
1804 * @len: number of bytes to write
1805 *
1806 * Read @len bytes to @buffer from the I/O channel.
1807 *
1808 * Returns the number of bytes written
1809 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001810int
Owen Taylor3473f882001-02-23 17:55:21 +00001811xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001812 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001813 return(xmlNanoHTTPRead(context, &buffer[0], len));
1814}
1815
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001816#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001817/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001818 * xmlIOHTTPWrite
1819 * @context: previously opened writing context
1820 * @buffer: data to output to temporary buffer
1821 * @len: bytes to output
1822 *
1823 * Collect data from memory buffer into a temporary file for later
1824 * processing.
1825 *
1826 * Returns number of bytes written.
1827 */
1828
1829static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001830xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001831
1832 xmlIOHTTPWriteCtxtPtr ctxt = context;
1833
1834 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1835 return ( -1 );
1836
1837 if ( len > 0 ) {
1838
1839 /* Use gzwrite or fwrite as previously setup in the open call */
1840
1841#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001842 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001843 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1844
1845 else
1846#endif
1847 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1848
1849 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001850 xmlChar msg[500];
1851 xmlStrPrintf(msg, 500,
1852 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001853 "Error appending to internal buffer.",
1854 "Error sending document to URI",
1855 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001856 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001857 }
1858 }
1859
1860 return ( len );
1861}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001862#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001863
1864
1865/**
Owen Taylor3473f882001-02-23 17:55:21 +00001866 * xmlIOHTTPClose:
1867 * @context: the I/O context
1868 *
1869 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001870 *
1871 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001872 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001873int
Owen Taylor3473f882001-02-23 17:55:21 +00001874xmlIOHTTPClose (void * context) {
1875 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001876 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001877}
Daniel Veillardf012a642001-07-23 19:10:52 +00001878
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001879#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001880/**
1881 * xmlIOHTTCloseWrite
1882 * @context: The I/O context
1883 * @http_mthd: The HTTP method to be used when sending the data
1884 *
1885 * Close the transmit HTTP I/O channel and actually send the data.
1886 */
1887static int
1888xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1889
1890 int close_rc = -1;
1891 int http_rtn = 0;
1892 int content_lgth = 0;
1893 xmlIOHTTPWriteCtxtPtr ctxt = context;
1894
1895 char * http_content = NULL;
1896 char * content_encoding = NULL;
1897 char * content_type = (char *) "text/xml";
1898 void * http_ctxt = NULL;
1899
1900 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1901 return ( -1 );
1902
1903 /* Retrieve the content from the appropriate buffer */
1904
1905#ifdef HAVE_ZLIB_H
1906
1907 if ( ctxt->compression > 0 ) {
1908 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1909 content_encoding = (char *) "Content-Encoding: gzip";
1910 }
1911 else
1912#endif
1913 {
1914 /* Pull the data out of the memory output buffer */
1915
1916 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1917 http_content = (char *)dctxt->buffer->content;
1918 content_lgth = dctxt->buffer->use;
1919 }
1920
1921 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001922 xmlChar msg[500];
1923 xmlStrPrintf(msg, 500,
1924 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1925 "Error retrieving content.\nUnable to",
1926 http_mthd, "data to URI", ctxt->uri );
1927 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001928 }
1929
1930 else {
1931
1932 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001933 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00001934 content_lgth );
1935
1936 if ( http_ctxt != NULL ) {
1937#ifdef DEBUG_HTTP
1938 /* If testing/debugging - dump reply with request content */
1939
1940 FILE * tst_file = NULL;
1941 char buffer[ 4096 ];
1942 char * dump_name = NULL;
1943 int avail;
1944
1945 xmlGenericError( xmlGenericErrorContext,
1946 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1947 http_mthd, ctxt->uri,
1948 xmlNanoHTTPReturnCode( http_ctxt ) );
1949
1950 /*
1951 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001952 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00001953 ** standard error context.
1954 */
1955
1956 dump_name = tempnam( NULL, "lxml" );
1957 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001958 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001959
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001960 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001961 if ( tst_file != NULL ) {
1962 xmlGenericError( xmlGenericErrorContext,
1963 "Transmitted content saved in file: %s\n", buffer );
1964
1965 fwrite( http_content, sizeof( char ),
1966 content_lgth, tst_file );
1967 fclose( tst_file );
1968 }
1969
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001970 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001971 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001972 if ( tst_file != NULL ) {
1973 xmlGenericError( xmlGenericErrorContext,
1974 "Reply content saved in file: %s\n", buffer );
1975
1976
1977 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1978 buffer, sizeof( buffer ) )) > 0 ) {
1979
1980 fwrite( buffer, sizeof( char ), avail, tst_file );
1981 }
1982
1983 fclose( tst_file );
1984 }
1985
1986 free( dump_name );
1987 }
1988#endif /* DEBUG_HTTP */
1989
1990 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1991 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1992 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001993 else {
1994 xmlChar msg[500];
1995 xmlStrPrintf(msg, 500,
1996 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001997 http_mthd, content_lgth,
1998 "bytes to URI", ctxt->uri,
1999 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002000 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2001 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002002
2003 xmlNanoHTTPClose( http_ctxt );
2004 xmlFree( content_type );
2005 }
2006 }
2007
2008 /* Final cleanups */
2009
2010 xmlFreeHTTPWriteCtxt( ctxt );
2011
2012 return ( close_rc );
2013}
2014
2015/**
2016 * xmlIOHTTPClosePut
2017 *
2018 * @context: The I/O context
2019 *
2020 * Close the transmit HTTP I/O channel and actually send data using a PUT
2021 * HTTP method.
2022 */
2023static int
2024xmlIOHTTPClosePut( void * ctxt ) {
2025 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2026}
2027
2028
2029/**
2030 * xmlIOHTTPClosePost
2031 *
2032 * @context: The I/O context
2033 *
2034 * Close the transmit HTTP I/O channel and actually send data using a POST
2035 * HTTP method.
2036 */
2037static int
2038xmlIOHTTPClosePost( void * ctxt ) {
2039 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2040}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002041#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002042
Owen Taylor3473f882001-02-23 17:55:21 +00002043#endif /* LIBXML_HTTP_ENABLED */
2044
2045#ifdef LIBXML_FTP_ENABLED
2046/************************************************************************
2047 * *
2048 * I/O for FTP file accesses *
2049 * *
2050 ************************************************************************/
2051/**
2052 * xmlIOFTPMatch:
2053 * @filename: the URI for matching
2054 *
2055 * check if the URI matches an FTP one
2056 *
2057 * Returns 1 if matches, 0 otherwise
2058 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002059int
Owen Taylor3473f882001-02-23 17:55:21 +00002060xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002061 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002062 return(1);
2063 return(0);
2064}
2065
2066/**
2067 * xmlIOFTPOpen:
2068 * @filename: the URI for matching
2069 *
2070 * open an FTP I/O channel
2071 *
2072 * Returns an I/O context or NULL in case of error
2073 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002074void *
Owen Taylor3473f882001-02-23 17:55:21 +00002075xmlIOFTPOpen (const char *filename) {
2076 return(xmlNanoFTPOpen(filename));
2077}
2078
2079/**
2080 * xmlIOFTPRead:
2081 * @context: the I/O context
2082 * @buffer: where to drop data
2083 * @len: number of bytes to write
2084 *
2085 * Read @len bytes to @buffer from the I/O channel.
2086 *
2087 * Returns the number of bytes written
2088 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002089int
Owen Taylor3473f882001-02-23 17:55:21 +00002090xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002091 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002092 return(xmlNanoFTPRead(context, &buffer[0], len));
2093}
2094
2095/**
2096 * xmlIOFTPClose:
2097 * @context: the I/O context
2098 *
2099 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002100 *
2101 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002102 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002103int
Owen Taylor3473f882001-02-23 17:55:21 +00002104xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002105 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002106}
2107#endif /* LIBXML_FTP_ENABLED */
2108
2109
2110/**
2111 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002112 * @matchFunc: the xmlInputMatchCallback
2113 * @openFunc: the xmlInputOpenCallback
2114 * @readFunc: the xmlInputReadCallback
2115 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002116 *
2117 * Register a new set of I/O callback for handling parser input.
2118 *
2119 * Returns the registered handler number or -1 in case of error
2120 */
2121int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002122xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2123 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2124 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002125 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2126 return(-1);
2127 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002128 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2129 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2130 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2131 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002132 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002133 return(xmlInputCallbackNr++);
2134}
2135
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002136#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002137/**
2138 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002139 * @matchFunc: the xmlOutputMatchCallback
2140 * @openFunc: the xmlOutputOpenCallback
2141 * @writeFunc: the xmlOutputWriteCallback
2142 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002143 *
2144 * Register a new set of I/O callback for handling output.
2145 *
2146 * Returns the registered handler number or -1 in case of error
2147 */
2148int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002149xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2150 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2151 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002152 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002153 return(-1);
2154 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002155 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2156 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2157 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2158 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002159 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002160 return(xmlOutputCallbackNr++);
2161}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002162#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002163
2164/**
2165 * xmlRegisterDefaultInputCallbacks:
2166 *
2167 * Registers the default compiled-in I/O handlers.
2168 */
2169void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002170xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002171 if (xmlInputCallbackInitialized)
2172 return;
2173
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002174#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2175 xmlInitPlatformSpecificIo();
2176#endif
2177
Owen Taylor3473f882001-02-23 17:55:21 +00002178 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2179 xmlFileRead, xmlFileClose);
2180#ifdef HAVE_ZLIB_H
2181 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2182 xmlGzfileRead, xmlGzfileClose);
2183#endif /* HAVE_ZLIB_H */
2184
2185#ifdef LIBXML_HTTP_ENABLED
2186 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2187 xmlIOHTTPRead, xmlIOHTTPClose);
2188#endif /* LIBXML_HTTP_ENABLED */
2189
2190#ifdef LIBXML_FTP_ENABLED
2191 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2192 xmlIOFTPRead, xmlIOFTPClose);
2193#endif /* LIBXML_FTP_ENABLED */
2194 xmlInputCallbackInitialized = 1;
2195}
2196
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002197#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002198/**
2199 * xmlRegisterDefaultOutputCallbacks:
2200 *
2201 * Registers the default compiled-in I/O handlers.
2202 */
2203void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002204xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002205 if (xmlOutputCallbackInitialized)
2206 return;
2207
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002208#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2209 xmlInitPlatformSpecificIo();
2210#endif
2211
Owen Taylor3473f882001-02-23 17:55:21 +00002212 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2213 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002214
2215#ifdef LIBXML_HTTP_ENABLED
2216 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2217 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2218#endif
2219
Owen Taylor3473f882001-02-23 17:55:21 +00002220/*********************************
2221 No way a-priori to distinguish between gzipped files from
2222 uncompressed ones except opening if existing then closing
2223 and saving with same compression ratio ... a pain.
2224
2225#ifdef HAVE_ZLIB_H
2226 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2227 xmlGzfileWrite, xmlGzfileClose);
2228#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002229
2230 Nor FTP PUT ....
2231#ifdef LIBXML_FTP_ENABLED
2232 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2233 xmlIOFTPWrite, xmlIOFTPClose);
2234#endif
2235 **********************************/
2236 xmlOutputCallbackInitialized = 1;
2237}
2238
Daniel Veillardf012a642001-07-23 19:10:52 +00002239#ifdef LIBXML_HTTP_ENABLED
2240/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002241 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002242 *
2243 * By default, libxml submits HTTP output requests using the "PUT" method.
2244 * Calling this method changes the HTTP output method to use the "POST"
2245 * method instead.
2246 *
2247 */
2248void
2249xmlRegisterHTTPPostCallbacks( void ) {
2250
2251 /* Register defaults if not done previously */
2252
2253 if ( xmlOutputCallbackInitialized == 0 )
2254 xmlRegisterDefaultOutputCallbacks( );
2255
2256 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2257 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2258 return;
2259}
2260#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002261#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002262
Owen Taylor3473f882001-02-23 17:55:21 +00002263/**
2264 * xmlAllocParserInputBuffer:
2265 * @enc: the charset encoding if known
2266 *
2267 * Create a buffered parser input for progressive parsing
2268 *
2269 * Returns the new parser input or NULL
2270 */
2271xmlParserInputBufferPtr
2272xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2273 xmlParserInputBufferPtr ret;
2274
2275 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2276 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002277 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002278 return(NULL);
2279 }
2280 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002281 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002282 if (ret->buffer == NULL) {
2283 xmlFree(ret);
2284 return(NULL);
2285 }
2286 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2287 ret->encoder = xmlGetCharEncodingHandler(enc);
2288 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002289 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002290 else
2291 ret->raw = NULL;
2292 ret->readcallback = NULL;
2293 ret->closecallback = NULL;
2294 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002295 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002296 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002297
2298 return(ret);
2299}
2300
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002301#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002302/**
2303 * xmlAllocOutputBuffer:
2304 * @encoder: the encoding converter or NULL
2305 *
2306 * Create a buffered parser output
2307 *
2308 * Returns the new parser output or NULL
2309 */
2310xmlOutputBufferPtr
2311xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2312 xmlOutputBufferPtr ret;
2313
2314 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2315 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002316 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002317 return(NULL);
2318 }
2319 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2320 ret->buffer = xmlBufferCreate();
2321 if (ret->buffer == NULL) {
2322 xmlFree(ret);
2323 return(NULL);
2324 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002325
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002326 /* try to avoid a performance problem with Windows realloc() */
2327 if (ret->buffer->alloc == XML_BUFFER_ALLOC_EXACT)
2328 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2329
Daniel Veillardda3fee42008-09-01 13:08:57 +00002330 ret->encoder = encoder;
2331 if (encoder != NULL) {
2332 ret->conv = xmlBufferCreateSize(4000);
2333 if (ret->conv == NULL) {
2334 xmlFree(ret);
2335 return(NULL);
2336 }
2337
2338 /*
2339 * This call is designed to initiate the encoder state
2340 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002341 xmlCharEncOutFunc(encoder, ret->conv, NULL);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002342 } else
2343 ret->conv = NULL;
2344 ret->writecallback = NULL;
2345 ret->closecallback = NULL;
2346 ret->context = NULL;
2347 ret->written = 0;
2348
2349 return(ret);
2350}
2351
2352/**
2353 * xmlAllocOutputBufferInternal:
2354 * @encoder: the encoding converter or NULL
2355 *
2356 * Create a buffered parser output
2357 *
2358 * Returns the new parser output or NULL
2359 */
2360xmlOutputBufferPtr
2361xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2362 xmlOutputBufferPtr ret;
2363
2364 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2365 if (ret == NULL) {
2366 xmlIOErrMemory("creating output buffer");
2367 return(NULL);
2368 }
2369 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2370 ret->buffer = xmlBufferCreate();
2371 if (ret->buffer == NULL) {
2372 xmlFree(ret);
2373 return(NULL);
2374 }
2375
2376
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002377 /*
2378 * For conversion buffers we use the special IO handling
Daniel Veillardda3fee42008-09-01 13:08:57 +00002379 * We don't do that from the exported API to avoid confusing
2380 * user's code.
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002381 */
2382 ret->buffer->alloc = XML_BUFFER_ALLOC_IO;
2383 ret->buffer->contentIO = ret->buffer->content;
2384
Owen Taylor3473f882001-02-23 17:55:21 +00002385 ret->encoder = encoder;
2386 if (encoder != NULL) {
2387 ret->conv = xmlBufferCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002388 if (ret->conv == NULL) {
2389 xmlFree(ret);
2390 return(NULL);
2391 }
2392
Owen Taylor3473f882001-02-23 17:55:21 +00002393 /*
2394 * This call is designed to initiate the encoder state
2395 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002396 xmlCharEncOutFunc(encoder, ret->conv, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002397 } else
2398 ret->conv = NULL;
2399 ret->writecallback = NULL;
2400 ret->closecallback = NULL;
2401 ret->context = NULL;
2402 ret->written = 0;
2403
2404 return(ret);
2405}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002406
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002407#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002408
2409/**
2410 * xmlFreeParserInputBuffer:
2411 * @in: a buffered parser input
2412 *
2413 * Free up the memory used by a buffered parser input
2414 */
2415void
2416xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002417 if (in == NULL) return;
2418
Owen Taylor3473f882001-02-23 17:55:21 +00002419 if (in->raw) {
2420 xmlBufferFree(in->raw);
2421 in->raw = NULL;
2422 }
2423 if (in->encoder != NULL) {
2424 xmlCharEncCloseFunc(in->encoder);
2425 }
2426 if (in->closecallback != NULL) {
2427 in->closecallback(in->context);
2428 }
2429 if (in->buffer != NULL) {
2430 xmlBufferFree(in->buffer);
2431 in->buffer = NULL;
2432 }
2433
Owen Taylor3473f882001-02-23 17:55:21 +00002434 xmlFree(in);
2435}
2436
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002437#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002438/**
2439 * xmlOutputBufferClose:
2440 * @out: a buffered output
2441 *
2442 * flushes and close the output I/O channel
2443 * and free up all the associated resources
2444 *
2445 * Returns the number of byte written or -1 in case of error.
2446 */
2447int
Daniel Veillard828ce832003-10-08 19:19:10 +00002448xmlOutputBufferClose(xmlOutputBufferPtr out)
2449{
Owen Taylor3473f882001-02-23 17:55:21 +00002450 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002451 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002452
2453 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002454 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002455 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002456 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002457 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002458 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002459 }
2460 written = out->written;
2461 if (out->conv) {
2462 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002463 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002464 }
2465 if (out->encoder != NULL) {
2466 xmlCharEncCloseFunc(out->encoder);
2467 }
2468 if (out->buffer != NULL) {
2469 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002470 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002471 }
2472
Daniel Veillard828ce832003-10-08 19:19:10 +00002473 if (out->error)
2474 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002475 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002476 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002477}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002478#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002479
Daniel Veillard1b243b42004-06-08 10:16:42 +00002480xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002481__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002482 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002483 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002484 void *context = NULL;
2485
2486 if (xmlInputCallbackInitialized == 0)
2487 xmlRegisterDefaultInputCallbacks();
2488
2489 if (URI == NULL) return(NULL);
2490
2491 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002492 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002493 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002494 */
2495 if (context == NULL) {
2496 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2497 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2498 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002499 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002500 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002501 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002502 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002503 }
Owen Taylor3473f882001-02-23 17:55:21 +00002504 }
2505 }
2506 if (context == NULL) {
2507 return(NULL);
2508 }
2509
2510 /*
2511 * Allocate the Input buffer front-end.
2512 */
2513 ret = xmlAllocParserInputBuffer(enc);
2514 if (ret != NULL) {
2515 ret->context = context;
2516 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2517 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002518#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002519 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2520 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002521 if (((z_stream *)context)->avail_in > 4) {
2522 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002523 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002524 if (gzread(context, buff4, 4) == 4) {
2525 if (strncmp(buff4, cptr, 4) == 0)
2526 ret->compressed = 0;
2527 else
2528 ret->compressed = 1;
2529 gzrewind(context);
2530 }
2531 }
2532 }
2533#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002534 }
William M. Brack42331a92004-07-29 07:07:16 +00002535 else
2536 xmlInputCallbackTable[i].closecallback (context);
2537
Owen Taylor3473f882001-02-23 17:55:21 +00002538 return(ret);
2539}
2540
2541/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002542 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002543 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002544 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002545 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002546 * Create a buffered parser input for the progressive parsing of a file
2547 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002548 * Automatic support for ZLIB/Compress compressed document is provided
2549 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002550 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002551 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002552 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002553 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002554xmlParserInputBufferPtr
2555xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2556 if ((xmlParserInputBufferCreateFilenameValue)) {
2557 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2558 }
2559 return __xmlParserInputBufferCreateFilename(URI, enc);
2560}
2561
2562#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002563xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002564__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002565 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002566 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002567 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002568 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002569 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002570 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002571 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002572#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002573 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002574#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002575
Owen Taylor3473f882001-02-23 17:55:21 +00002576 if (xmlOutputCallbackInitialized == 0)
2577 xmlRegisterDefaultOutputCallbacks();
2578
2579 if (URI == NULL) return(NULL);
2580
Daniel Veillard966a31e2004-05-09 02:58:44 +00002581 puri = xmlParseURI(URI);
2582 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002583#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002584 if ((puri->scheme != NULL) &&
2585 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002586 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002587#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002588 /*
2589 * try to limit the damages of the URI unescaping code.
2590 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002591 if ((puri->scheme == NULL) ||
2592 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002593 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2594 xmlFreeURI(puri);
2595 }
Owen Taylor3473f882001-02-23 17:55:21 +00002596
2597 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002598 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002599 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002600 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002601 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002602 if (unescaped != NULL) {
2603#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002604 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002605 context = xmlGzfileOpenW(unescaped, compression);
2606 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002607 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002608 if (ret != NULL) {
2609 ret->context = context;
2610 ret->writecallback = xmlGzfileWrite;
2611 ret->closecallback = xmlGzfileClose;
2612 }
2613 xmlFree(unescaped);
2614 return(ret);
2615 }
2616 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002617#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002618 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2619 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2620 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2621#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2622 /* Need to pass compression parameter into HTTP open calls */
2623 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2624 context = xmlIOHTTPOpenW(unescaped, compression);
2625 else
2626#endif
2627 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2628 if (context != NULL)
2629 break;
2630 }
2631 }
2632 xmlFree(unescaped);
2633 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002634
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002635 /*
2636 * If this failed try with a non-escaped URI this may be a strange
2637 * filename
2638 */
2639 if (context == NULL) {
2640#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002641 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002642 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002643 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002644 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002645 if (ret != NULL) {
2646 ret->context = context;
2647 ret->writecallback = xmlGzfileWrite;
2648 ret->closecallback = xmlGzfileClose;
2649 }
2650 return(ret);
2651 }
2652 }
2653#endif
2654 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2655 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002656 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002657#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2658 /* Need to pass compression parameter into HTTP open calls */
2659 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2660 context = xmlIOHTTPOpenW(URI, compression);
2661 else
2662#endif
2663 context = xmlOutputCallbackTable[i].opencallback(URI);
2664 if (context != NULL)
2665 break;
2666 }
Owen Taylor3473f882001-02-23 17:55:21 +00002667 }
2668 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002669
Owen Taylor3473f882001-02-23 17:55:21 +00002670 if (context == NULL) {
2671 return(NULL);
2672 }
2673
2674 /*
2675 * Allocate the Output buffer front-end.
2676 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002677 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002678 if (ret != NULL) {
2679 ret->context = context;
2680 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2681 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2682 }
2683 return(ret);
2684}
Daniel Veillard0335a842004-06-02 16:18:40 +00002685
2686/**
2687 * xmlOutputBufferCreateFilename:
2688 * @URI: a C string containing the URI or filename
2689 * @encoder: the encoding converter or NULL
2690 * @compression: the compression ration (0 none, 9 max).
2691 *
2692 * Create a buffered output for the progressive saving of a file
2693 * If filename is "-' then we use stdout as the output.
2694 * Automatic support for ZLIB/Compress compressed document is provided
2695 * by default if found at compile-time.
2696 * TODO: currently if compression is set, the library only support
2697 * writing to a local file.
2698 *
2699 * Returns the new output or NULL
2700 */
2701xmlOutputBufferPtr
2702xmlOutputBufferCreateFilename(const char *URI,
2703 xmlCharEncodingHandlerPtr encoder,
2704 int compression ATTRIBUTE_UNUSED) {
2705 if ((xmlOutputBufferCreateFilenameValue)) {
2706 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2707 }
2708 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2709}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002710#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002711
2712/**
2713 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002714 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002715 * @enc: the charset encoding if known
2716 *
2717 * Create a buffered parser input for the progressive parsing of a FILE *
2718 * buffered C I/O
2719 *
2720 * Returns the new parser input or NULL
2721 */
2722xmlParserInputBufferPtr
2723xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2724 xmlParserInputBufferPtr ret;
2725
2726 if (xmlInputCallbackInitialized == 0)
2727 xmlRegisterDefaultInputCallbacks();
2728
2729 if (file == NULL) return(NULL);
2730
2731 ret = xmlAllocParserInputBuffer(enc);
2732 if (ret != NULL) {
2733 ret->context = file;
2734 ret->readcallback = xmlFileRead;
2735 ret->closecallback = xmlFileFlush;
2736 }
2737
2738 return(ret);
2739}
2740
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002741#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002742/**
2743 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002744 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002745 * @encoder: the encoding converter or NULL
2746 *
2747 * Create a buffered output for the progressive saving to a FILE *
2748 * buffered C I/O
2749 *
2750 * Returns the new parser output or NULL
2751 */
2752xmlOutputBufferPtr
2753xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2754 xmlOutputBufferPtr ret;
2755
2756 if (xmlOutputCallbackInitialized == 0)
2757 xmlRegisterDefaultOutputCallbacks();
2758
2759 if (file == NULL) return(NULL);
2760
Daniel Veillardda3fee42008-09-01 13:08:57 +00002761 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002762 if (ret != NULL) {
2763 ret->context = file;
2764 ret->writecallback = xmlFileWrite;
2765 ret->closecallback = xmlFileFlush;
2766 }
2767
2768 return(ret);
2769}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002770
2771/**
2772 * xmlOutputBufferCreateBuffer:
2773 * @buffer: a xmlBufferPtr
2774 * @encoder: the encoding converter or NULL
2775 *
2776 * Create a buffered output for the progressive saving to a xmlBuffer
2777 *
2778 * Returns the new parser output or NULL
2779 */
2780xmlOutputBufferPtr
2781xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2782 xmlCharEncodingHandlerPtr encoder) {
2783 xmlOutputBufferPtr ret;
2784
2785 if (buffer == NULL) return(NULL);
2786
Rob Richardsa44f2342005-11-09 18:03:45 +00002787 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2788 xmlBufferWrite,
2789 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002790 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002791
2792 return(ret);
2793}
2794
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002795#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002796
2797/**
2798 * xmlParserInputBufferCreateFd:
2799 * @fd: a file descriptor number
2800 * @enc: the charset encoding if known
2801 *
2802 * Create a buffered parser input for the progressive parsing for the input
2803 * from a file descriptor
2804 *
2805 * Returns the new parser input or NULL
2806 */
2807xmlParserInputBufferPtr
2808xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2809 xmlParserInputBufferPtr ret;
2810
2811 if (fd < 0) return(NULL);
2812
2813 ret = xmlAllocParserInputBuffer(enc);
2814 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002815 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002816 ret->readcallback = xmlFdRead;
2817 ret->closecallback = xmlFdClose;
2818 }
2819
2820 return(ret);
2821}
2822
2823/**
2824 * xmlParserInputBufferCreateMem:
2825 * @mem: the memory input
2826 * @size: the length of the memory block
2827 * @enc: the charset encoding if known
2828 *
2829 * Create a buffered parser input for the progressive parsing for the input
2830 * from a memory area.
2831 *
2832 * Returns the new parser input or NULL
2833 */
2834xmlParserInputBufferPtr
2835xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2836 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002837 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002838
2839 if (size <= 0) return(NULL);
2840 if (mem == NULL) return(NULL);
2841
2842 ret = xmlAllocParserInputBuffer(enc);
2843 if (ret != NULL) {
2844 ret->context = (void *) mem;
2845 ret->readcallback = (xmlInputReadCallback) xmlNop;
2846 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002847 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2848 if (errcode != 0) {
2849 xmlFree(ret);
2850 return(NULL);
2851 }
Owen Taylor3473f882001-02-23 17:55:21 +00002852 }
2853
2854 return(ret);
2855}
2856
2857/**
Daniel Veillard53350552003-09-18 13:35:51 +00002858 * xmlParserInputBufferCreateStatic:
2859 * @mem: the memory input
2860 * @size: the length of the memory block
2861 * @enc: the charset encoding if known
2862 *
2863 * Create a buffered parser input for the progressive parsing for the input
2864 * from an immutable memory area. This will not copy the memory area to
2865 * the buffer, but the memory is expected to be available until the end of
2866 * the parsing, this is useful for example when using mmap'ed file.
2867 *
2868 * Returns the new parser input or NULL
2869 */
2870xmlParserInputBufferPtr
2871xmlParserInputBufferCreateStatic(const char *mem, int size,
2872 xmlCharEncoding enc) {
2873 xmlParserInputBufferPtr ret;
2874
2875 if (size <= 0) return(NULL);
2876 if (mem == NULL) return(NULL);
2877
2878 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2879 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002880 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002881 return(NULL);
2882 }
2883 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002884 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002885 if (ret->buffer == NULL) {
2886 xmlFree(ret);
2887 return(NULL);
2888 }
2889 ret->encoder = xmlGetCharEncodingHandler(enc);
2890 if (ret->encoder != NULL)
2891 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2892 else
2893 ret->raw = NULL;
2894 ret->compressed = -1;
2895 ret->context = (void *) mem;
2896 ret->readcallback = NULL;
2897 ret->closecallback = NULL;
2898
2899 return(ret);
2900}
2901
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002902#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002903/**
Owen Taylor3473f882001-02-23 17:55:21 +00002904 * xmlOutputBufferCreateFd:
2905 * @fd: a file descriptor number
2906 * @encoder: the encoding converter or NULL
2907 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002908 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00002909 * to a file descriptor
2910 *
2911 * Returns the new parser output or NULL
2912 */
2913xmlOutputBufferPtr
2914xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2915 xmlOutputBufferPtr ret;
2916
2917 if (fd < 0) return(NULL);
2918
Daniel Veillardda3fee42008-09-01 13:08:57 +00002919 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002920 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002921 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002922 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002923 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002924 }
2925
2926 return(ret);
2927}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002928#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002929
2930/**
2931 * xmlParserInputBufferCreateIO:
2932 * @ioread: an I/O read function
2933 * @ioclose: an I/O close function
2934 * @ioctx: an I/O handler
2935 * @enc: the charset encoding if known
2936 *
2937 * Create a buffered parser input for the progressive parsing for the input
2938 * from an I/O handler
2939 *
2940 * Returns the new parser input or NULL
2941 */
2942xmlParserInputBufferPtr
2943xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2944 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2945 xmlParserInputBufferPtr ret;
2946
2947 if (ioread == NULL) return(NULL);
2948
2949 ret = xmlAllocParserInputBuffer(enc);
2950 if (ret != NULL) {
2951 ret->context = (void *) ioctx;
2952 ret->readcallback = ioread;
2953 ret->closecallback = ioclose;
2954 }
2955
2956 return(ret);
2957}
2958
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002959#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002960/**
2961 * xmlOutputBufferCreateIO:
2962 * @iowrite: an I/O write function
2963 * @ioclose: an I/O close function
2964 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002965 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002966 *
2967 * Create a buffered output for the progressive saving
2968 * to an I/O handler
2969 *
2970 * Returns the new parser output or NULL
2971 */
2972xmlOutputBufferPtr
2973xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2974 xmlOutputCloseCallback ioclose, void *ioctx,
2975 xmlCharEncodingHandlerPtr encoder) {
2976 xmlOutputBufferPtr ret;
2977
2978 if (iowrite == NULL) return(NULL);
2979
Daniel Veillardda3fee42008-09-01 13:08:57 +00002980 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002981 if (ret != NULL) {
2982 ret->context = (void *) ioctx;
2983 ret->writecallback = iowrite;
2984 ret->closecallback = ioclose;
2985 }
2986
2987 return(ret);
2988}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002989#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002990
2991/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002992 * xmlParserInputBufferCreateFilenameDefault:
2993 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2994 *
2995 * Registers a callback for URI input file handling
2996 *
2997 * Returns the old value of the registration function
2998 */
2999xmlParserInputBufferCreateFilenameFunc
3000xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3001{
3002 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3003 if (old == NULL) {
3004 old = __xmlParserInputBufferCreateFilename;
3005 }
3006
3007 xmlParserInputBufferCreateFilenameValue = func;
3008 return(old);
3009}
3010
3011/**
3012 * xmlOutputBufferCreateFilenameDefault:
3013 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3014 *
3015 * Registers a callback for URI output file handling
3016 *
3017 * Returns the old value of the registration function
3018 */
3019xmlOutputBufferCreateFilenameFunc
3020xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3021{
3022 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3023#ifdef LIBXML_OUTPUT_ENABLED
3024 if (old == NULL) {
3025 old = __xmlOutputBufferCreateFilename;
3026 }
3027#endif
3028 xmlOutputBufferCreateFilenameValue = func;
3029 return(old);
3030}
3031
3032/**
Owen Taylor3473f882001-02-23 17:55:21 +00003033 * xmlParserInputBufferPush:
3034 * @in: a buffered parser input
3035 * @len: the size in bytes of the array.
3036 * @buf: an char array
3037 *
3038 * Push the content of the arry in the input buffer
3039 * This routine handle the I18N transcoding to internal UTF-8
3040 * This is used when operating the parser in progressive (push) mode.
3041 *
3042 * Returns the number of chars read and stored in the buffer, or -1
3043 * in case of error.
3044 */
3045int
3046xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3047 int len, const char *buf) {
3048 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003049 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003050
3051 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003052 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003053 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003054 unsigned int use;
3055
Owen Taylor3473f882001-02-23 17:55:21 +00003056 /*
3057 * Store the data in the incoming raw buffer
3058 */
3059 if (in->raw == NULL) {
3060 in->raw = xmlBufferCreate();
3061 }
William M. Bracka3215c72004-07-31 16:24:01 +00003062 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
3063 if (ret != 0)
3064 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003065
3066 /*
3067 * convert as much as possible to the parser reading buffer.
3068 */
Daniel Veillard36711902004-02-11 13:25:26 +00003069 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003070 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3071 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003072 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003073 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003074 return(-1);
3075 }
Daniel Veillard36711902004-02-11 13:25:26 +00003076 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003077 } else {
3078 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00003079 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
3080 if (ret != 0)
3081 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003082 }
3083#ifdef DEBUG_INPUT
3084 xmlGenericError(xmlGenericErrorContext,
3085 "I/O: pushed %d chars, buffer %d/%d\n",
3086 nbchars, in->buffer->use, in->buffer->size);
3087#endif
3088 return(nbchars);
3089}
3090
3091/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003092 * endOfInput:
3093 *
3094 * When reading from an Input channel indicated end of file or error
3095 * don't reread from it again.
3096 */
3097static int
3098endOfInput (void * context ATTRIBUTE_UNUSED,
3099 char * buffer ATTRIBUTE_UNUSED,
3100 int len ATTRIBUTE_UNUSED) {
3101 return(0);
3102}
3103
3104/**
Owen Taylor3473f882001-02-23 17:55:21 +00003105 * xmlParserInputBufferGrow:
3106 * @in: a buffered parser input
3107 * @len: indicative value of the amount of chars to read
3108 *
3109 * Grow up the content of the input buffer, the old data are preserved
3110 * This routine handle the I18N transcoding to internal UTF-8
3111 * This routine is used when operating the parser in normal (pull) mode
3112 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003113 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003114 * onto in->buffer or in->raw
3115 *
3116 * Returns the number of chars read and stored in the buffer, or -1
3117 * in case of error.
3118 */
3119int
3120xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3121 char *buffer = NULL;
3122 int res = 0;
3123 int nbchars = 0;
3124 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00003125 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00003126
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003127 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003128 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003129 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003130
Owen Taylor3473f882001-02-23 17:55:21 +00003131 buffree = in->buffer->size - in->buffer->use;
3132 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003133 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003134 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003135 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003136 }
Owen Taylor3473f882001-02-23 17:55:21 +00003137
Daniel Veillarde5354492002-05-16 08:43:22 +00003138 needSize = in->buffer->use + len + 1;
3139 if (needSize > in->buffer->size){
3140 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003141 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003142 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003143 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003144 }
Owen Taylor3473f882001-02-23 17:55:21 +00003145 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003146 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003147
3148 /*
3149 * Call the read method for this I/O type.
3150 */
3151 if (in->readcallback != NULL) {
3152 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003153 if (res <= 0)
3154 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003155 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003156 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003157 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003158 return(-1);
3159 }
3160 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003161 return(-1);
3162 }
3163 len = res;
3164 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003165 unsigned int use;
3166
Owen Taylor3473f882001-02-23 17:55:21 +00003167 /*
3168 * Store the data in the incoming raw buffer
3169 */
3170 if (in->raw == NULL) {
3171 in->raw = xmlBufferCreate();
3172 }
William M. Bracka3215c72004-07-31 16:24:01 +00003173 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3174 if (res != 0)
3175 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003176
3177 /*
3178 * convert as much as possible to the parser reading buffer.
3179 */
Daniel Veillard36711902004-02-11 13:25:26 +00003180 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003181 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3182 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003183 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003184 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003185 return(-1);
3186 }
Daniel Veillard36711902004-02-11 13:25:26 +00003187 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003188 } else {
3189 nbchars = len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003190 in->buffer->use += nbchars;
Daniel Veillarde5354492002-05-16 08:43:22 +00003191 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003192 }
3193#ifdef DEBUG_INPUT
3194 xmlGenericError(xmlGenericErrorContext,
3195 "I/O: read %d chars, buffer %d/%d\n",
3196 nbchars, in->buffer->use, in->buffer->size);
3197#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003198 return(nbchars);
3199}
3200
3201/**
3202 * xmlParserInputBufferRead:
3203 * @in: a buffered parser input
3204 * @len: indicative value of the amount of chars to read
3205 *
3206 * Refresh the content of the input buffer, the old data are considered
3207 * consumed
3208 * This routine handle the I18N transcoding to internal UTF-8
3209 *
3210 * Returns the number of chars read and stored in the buffer, or -1
3211 * in case of error.
3212 */
3213int
3214xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003215 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003216 if (in->readcallback != NULL)
3217 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003218 else if ((in->buffer != NULL) &&
3219 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3220 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003221 else
3222 return(-1);
3223}
3224
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003225#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003226/**
3227 * xmlOutputBufferWrite:
3228 * @out: a buffered parser output
3229 * @len: the size in bytes of the array.
3230 * @buf: an char array
3231 *
3232 * Write the content of the array in the output I/O buffer
3233 * This routine handle the I18N transcoding from internal UTF-8
3234 * The buffer is lossless, i.e. will store in case of partial
3235 * or delayed writes.
3236 *
3237 * Returns the number of chars immediately written, or -1
3238 * in case of error.
3239 */
3240int
3241xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3242 int nbchars = 0; /* number of chars to output to I/O */
3243 int ret; /* return from function call */
3244 int written = 0; /* number of char written to I/O so far */
3245 int chunk; /* number of byte curreent processed from buf */
3246
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003247 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003248 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003249 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003250
3251 do {
3252 chunk = len;
3253 if (chunk > 4 * MINLEN)
3254 chunk = 4 * MINLEN;
3255
3256 /*
3257 * first handle encoding stuff.
3258 */
3259 if (out->encoder != NULL) {
3260 /*
3261 * Store the data in the incoming raw buffer
3262 */
3263 if (out->conv == NULL) {
3264 out->conv = xmlBufferCreate();
3265 }
William M. Bracka3215c72004-07-31 16:24:01 +00003266 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3267 if (ret != 0)
3268 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003269
3270 if ((out->buffer->use < MINLEN) && (chunk == len))
3271 goto done;
3272
3273 /*
3274 * convert as much as possible to the parser reading buffer.
3275 */
3276 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003277 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003278 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003279 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003280 return(-1);
3281 }
3282 nbchars = out->conv->use;
3283 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003284 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3285 if (ret != 0)
3286 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003287 nbchars = out->buffer->use;
3288 }
3289 buf += chunk;
3290 len -= chunk;
3291
3292 if ((nbchars < MINLEN) && (len <= 0))
3293 goto done;
3294
3295 if (out->writecallback) {
3296 /*
3297 * second write the stuff to the I/O channel
3298 */
3299 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003300 ret = out->writecallback(out->context,
Owen Taylor3473f882001-02-23 17:55:21 +00003301 (const char *)out->conv->content, nbchars);
3302 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003303 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003304 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003305 ret = out->writecallback(out->context,
Owen Taylor3473f882001-02-23 17:55:21 +00003306 (const char *)out->buffer->content, nbchars);
3307 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003308 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003309 }
3310 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003311 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003312 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003313 return(ret);
3314 }
3315 out->written += ret;
3316 }
3317 written += nbchars;
3318 } while (len > 0);
3319
3320done:
3321#ifdef DEBUG_INPUT
3322 xmlGenericError(xmlGenericErrorContext,
3323 "I/O: wrote %d chars\n", written);
3324#endif
3325 return(written);
3326}
3327
3328/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003329 * xmlEscapeContent:
3330 * @out: a pointer to an array of bytes to store the result
3331 * @outlen: the length of @out
3332 * @in: a pointer to an array of unescaped UTF-8 bytes
3333 * @inlen: the length of @in
3334 *
3335 * Take a block of UTF-8 chars in and escape them.
3336 * Returns 0 if success, or -1 otherwise
3337 * The value of @inlen after return is the number of octets consumed
3338 * if the return value is positive, else unpredictable.
3339 * The value of @outlen after return is the number of octets consumed.
3340 */
3341static int
3342xmlEscapeContent(unsigned char* out, int *outlen,
3343 const xmlChar* in, int *inlen) {
3344 unsigned char* outstart = out;
3345 const unsigned char* base = in;
3346 unsigned char* outend = out + *outlen;
3347 const unsigned char* inend;
3348
3349 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003350
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003351 while ((in < inend) && (out < outend)) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003352 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003353 if (outend - out < 4) break;
3354 *out++ = '&';
3355 *out++ = 'l';
3356 *out++ = 't';
3357 *out++ = ';';
3358 } else if (*in == '>') {
3359 if (outend - out < 4) break;
3360 *out++ = '&';
3361 *out++ = 'g';
3362 *out++ = 't';
3363 *out++ = ';';
3364 } else if (*in == '&') {
3365 if (outend - out < 5) break;
3366 *out++ = '&';
3367 *out++ = 'a';
3368 *out++ = 'm';
3369 *out++ = 'p';
3370 *out++ = ';';
3371 } else if (*in == '\r') {
3372 if (outend - out < 5) break;
3373 *out++ = '&';
3374 *out++ = '#';
3375 *out++ = '1';
3376 *out++ = '3';
3377 *out++ = ';';
3378 } else {
3379 *out++ = (unsigned char) *in;
3380 }
3381 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003382 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003383 *outlen = out - outstart;
3384 *inlen = in - base;
3385 return(0);
3386}
3387
3388/**
3389 * xmlOutputBufferWriteEscape:
3390 * @out: a buffered parser output
3391 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003392 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003393 *
3394 * Write the content of the string in the output I/O buffer
3395 * This routine escapes the caracters and then handle the I18N
3396 * 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
Daniel Veillardee8960b2004-05-14 03:25:14 +00003404xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3405 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003406 int nbchars = 0; /* number of chars to output to I/O */
3407 int ret; /* return from function call */
3408 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003409 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003410 int chunk; /* number of byte currently processed from str */
3411 int len; /* number of bytes in str */
3412 int cons; /* byte from str consumed */
3413
Daniel Veillardce244ad2004-11-05 10:03:46 +00003414 if ((out == NULL) || (out->error) || (str == NULL) ||
3415 (out->buffer == NULL) ||
3416 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003417 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003418 if (len < 0) return(0);
3419 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003420 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003421
3422 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003423 oldwritten = written;
3424
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003425 /*
3426 * how many bytes to consume and how many bytes to store.
3427 */
3428 cons = len;
3429 chunk = (out->buffer->size - out->buffer->use) - 1;
3430
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003431 /*
3432 * make sure we have enough room to save first, if this is
3433 * not the case force a flush, but make sure we stay in the loop
3434 */
3435 if (chunk < 40) {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003436 if (xmlBufferGrow(out->buffer, out->buffer->size + 100) < 0)
3437 return(-1);
3438 oldwritten = -1;
3439 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003440 }
3441
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003442 /*
3443 * first handle encoding stuff.
3444 */
3445 if (out->encoder != NULL) {
3446 /*
3447 * Store the data in the incoming raw buffer
3448 */
3449 if (out->conv == NULL) {
3450 out->conv = xmlBufferCreate();
3451 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003452 ret = escaping(out->buffer->content + out->buffer->use ,
3453 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003454 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003455 return(-1);
3456 out->buffer->use += chunk;
3457 out->buffer->content[out->buffer->use] = 0;
3458
3459 if ((out->buffer->use < MINLEN) && (cons == len))
3460 goto done;
3461
3462 /*
3463 * convert as much as possible to the output buffer.
3464 */
3465 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3466 if ((ret < 0) && (ret != -3)) {
3467 xmlIOErr(XML_IO_ENCODER, NULL);
3468 out->error = XML_IO_ENCODER;
3469 return(-1);
3470 }
3471 nbchars = out->conv->use;
3472 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003473 ret = escaping(out->buffer->content + out->buffer->use ,
3474 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003475 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003476 return(-1);
3477 out->buffer->use += chunk;
3478 out->buffer->content[out->buffer->use] = 0;
3479 nbchars = out->buffer->use;
3480 }
3481 str += cons;
3482 len -= cons;
3483
3484 if ((nbchars < MINLEN) && (len <= 0))
3485 goto done;
3486
3487 if (out->writecallback) {
3488 /*
3489 * second write the stuff to the I/O channel
3490 */
3491 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003492 ret = out->writecallback(out->context,
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003493 (const char *)out->conv->content, nbchars);
3494 if (ret >= 0)
3495 xmlBufferShrink(out->conv, ret);
3496 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003497 ret = out->writecallback(out->context,
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003498 (const char *)out->buffer->content, nbchars);
3499 if (ret >= 0)
3500 xmlBufferShrink(out->buffer, ret);
3501 }
3502 if (ret < 0) {
3503 xmlIOErr(XML_IO_WRITE, NULL);
3504 out->error = XML_IO_WRITE;
3505 return(ret);
3506 }
3507 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003508 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3509 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003510 }
3511 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003512 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003513
3514done:
3515#ifdef DEBUG_INPUT
3516 xmlGenericError(xmlGenericErrorContext,
3517 "I/O: wrote %d chars\n", written);
3518#endif
3519 return(written);
3520}
3521
3522/**
Owen Taylor3473f882001-02-23 17:55:21 +00003523 * xmlOutputBufferWriteString:
3524 * @out: a buffered parser output
3525 * @str: a zero terminated C string
3526 *
3527 * Write the content of the string in the output I/O buffer
3528 * This routine handle the I18N transcoding from internal UTF-8
3529 * The buffer is lossless, i.e. will store in case of partial
3530 * or delayed writes.
3531 *
3532 * Returns the number of chars immediately written, or -1
3533 * in case of error.
3534 */
3535int
3536xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3537 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003538
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003539 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003540 if (str == NULL)
3541 return(-1);
3542 len = strlen(str);
3543
3544 if (len > 0)
3545 return(xmlOutputBufferWrite(out, len, str));
3546 return(len);
3547}
3548
3549/**
3550 * xmlOutputBufferFlush:
3551 * @out: a buffered output
3552 *
3553 * flushes the output I/O channel
3554 *
3555 * Returns the number of byte written or -1 in case of error.
3556 */
3557int
3558xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3559 int nbchars = 0, ret = 0;
3560
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003561 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003562 /*
3563 * first handle encoding stuff.
3564 */
3565 if ((out->conv != NULL) && (out->encoder != NULL)) {
3566 /*
3567 * convert as much as possible to the parser reading buffer.
3568 */
3569 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3570 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003571 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003572 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003573 return(-1);
3574 }
3575 }
3576
3577 /*
3578 * second flush the stuff to the I/O channel
3579 */
3580 if ((out->conv != NULL) && (out->encoder != NULL) &&
3581 (out->writecallback != NULL)) {
3582 ret = out->writecallback(out->context,
3583 (const char *)out->conv->content, out->conv->use);
3584 if (ret >= 0)
3585 xmlBufferShrink(out->conv, ret);
3586 } else if (out->writecallback != NULL) {
3587 ret = out->writecallback(out->context,
3588 (const char *)out->buffer->content, out->buffer->use);
3589 if (ret >= 0)
3590 xmlBufferShrink(out->buffer, ret);
3591 }
3592 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003593 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003594 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003595 return(ret);
3596 }
3597 out->written += ret;
3598
3599#ifdef DEBUG_INPUT
3600 xmlGenericError(xmlGenericErrorContext,
3601 "I/O: flushed %d chars\n", ret);
3602#endif
3603 return(ret);
3604}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003605#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003606
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003607/**
Owen Taylor3473f882001-02-23 17:55:21 +00003608 * xmlParserGetDirectory:
3609 * @filename: the path to a file
3610 *
3611 * lookup the directory for that file
3612 *
3613 * Returns a new allocated string containing the directory, or NULL.
3614 */
3615char *
3616xmlParserGetDirectory(const char *filename) {
3617 char *ret = NULL;
3618 char dir[1024];
3619 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003620
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003621#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3622 return NULL;
3623#endif
3624
Owen Taylor3473f882001-02-23 17:55:21 +00003625 if (xmlInputCallbackInitialized == 0)
3626 xmlRegisterDefaultInputCallbacks();
3627
3628 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003629
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003630#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003631# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3632#else
3633# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003634#endif
3635
3636 strncpy(dir, filename, 1023);
3637 dir[1023] = 0;
3638 cur = &dir[strlen(dir)];
3639 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003640 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003641 cur --;
3642 }
Rob Richardsf779da32007-08-14 09:41:21 +00003643 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003644 if (cur == dir) dir[1] = 0;
3645 else *cur = 0;
3646 ret = xmlMemStrdup(dir);
3647 } else {
3648 if (getcwd(dir, 1024) != NULL) {
3649 dir[1023] = 0;
3650 ret = xmlMemStrdup(dir);
3651 }
3652 }
3653 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003654#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003655}
3656
3657/****************************************************************
3658 * *
3659 * External entities loading *
3660 * *
3661 ****************************************************************/
3662
Daniel Veillarda840b692003-10-19 13:35:37 +00003663/**
3664 * xmlCheckHTTPInput:
3665 * @ctxt: an XML parser context
3666 * @ret: an XML parser input
3667 *
3668 * Check an input in case it was created from an HTTP stream, in that
3669 * case it will handle encoding and update of the base URL in case of
3670 * redirection. It also checks for HTTP errors in which case the input
3671 * is cleanly freed up and an appropriate error is raised in context
3672 *
3673 * Returns the input or NULL in case of HTTP error.
3674 */
3675xmlParserInputPtr
3676xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3677#ifdef LIBXML_HTTP_ENABLED
3678 if ((ret != NULL) && (ret->buf != NULL) &&
3679 (ret->buf->readcallback == xmlIOHTTPRead) &&
3680 (ret->buf->context != NULL)) {
3681 const char *encoding;
3682 const char *redir;
3683 const char *mime;
3684 int code;
3685
3686 code = xmlNanoHTTPReturnCode(ret->buf->context);
3687 if (code >= 400) {
3688 /* fatal error */
3689 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003690 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003691 (const char *) ret->filename);
3692 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003693 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003694 xmlFreeInputStream(ret);
3695 ret = NULL;
3696 } else {
3697
3698 mime = xmlNanoHTTPMimeType(ret->buf->context);
3699 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3700 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3701 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3702 if (encoding != NULL) {
3703 xmlCharEncodingHandlerPtr handler;
3704
3705 handler = xmlFindCharEncodingHandler(encoding);
3706 if (handler != NULL) {
3707 xmlSwitchInputEncoding(ctxt, ret, handler);
3708 } else {
3709 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3710 "Unknown encoding %s",
3711 BAD_CAST encoding, NULL);
3712 }
3713 if (ret->encoding == NULL)
3714 ret->encoding = xmlStrdup(BAD_CAST encoding);
3715 }
3716#if 0
3717 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3718#endif
3719 }
3720 redir = xmlNanoHTTPRedir(ret->buf->context);
3721 if (redir != NULL) {
3722 if (ret->filename != NULL)
3723 xmlFree((xmlChar *) ret->filename);
3724 if (ret->directory != NULL) {
3725 xmlFree((xmlChar *) ret->directory);
3726 ret->directory = NULL;
3727 }
3728 ret->filename =
3729 (char *) xmlStrdup((const xmlChar *) redir);
3730 }
3731 }
3732 }
3733#endif
3734 return(ret);
3735}
3736
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003737static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003738 const char *path;
3739
3740 if (URL == NULL)
3741 return(0);
3742
Daniel Veillardf4862f02002-09-10 11:13:43 +00003743 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003744#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003745 path = &URL[17];
3746#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003747 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003748#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003749 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003750#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003751 path = &URL[8];
3752#else
3753 path = &URL[7];
3754#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003755 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003756 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003757
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003758 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003759}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003760
Daniel Veillardad4e2962006-09-21 08:36:38 +00003761#ifdef LIBXML_CATALOG_ENABLED
3762
3763/**
3764 * xmlResolveResourceFromCatalog:
3765 * @URL: the URL for the entity to load
3766 * @ID: the System ID for the entity to load
3767 * @ctxt: the context in which the entity is called or NULL
3768 *
3769 * Resolves the URL and ID against the appropriate catalog.
3770 * This function is used by xmlDefaultExternalEntityLoader and
3771 * xmlNoNetExternalEntityLoader.
3772 *
3773 * Returns a new allocated URL, or NULL.
3774 */
William M. Brack38d452a2007-05-22 16:00:06 +00003775static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003776xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3777 xmlParserCtxtPtr ctxt) {
3778 xmlChar *resource = NULL;
3779 xmlCatalogAllow pref;
3780
3781 /*
3782 * If the resource doesn't exists as a file,
3783 * try to load it from the resource pointed in the catalogs
3784 */
3785 pref = xmlCatalogGetDefaults();
3786
3787 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3788 /*
3789 * Do a local lookup
3790 */
3791 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3792 ((pref == XML_CATA_ALLOW_ALL) ||
3793 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3794 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3795 (const xmlChar *)ID,
3796 (const xmlChar *)URL);
3797 }
3798 /*
3799 * Try a global lookup
3800 */
3801 if ((resource == NULL) &&
3802 ((pref == XML_CATA_ALLOW_ALL) ||
3803 (pref == XML_CATA_ALLOW_GLOBAL))) {
3804 resource = xmlCatalogResolve((const xmlChar *)ID,
3805 (const xmlChar *)URL);
3806 }
3807 if ((resource == NULL) && (URL != NULL))
3808 resource = xmlStrdup((const xmlChar *) URL);
3809
3810 /*
3811 * TODO: do an URI lookup on the reference
3812 */
3813 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3814 xmlChar *tmp = NULL;
3815
3816 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3817 ((pref == XML_CATA_ALLOW_ALL) ||
3818 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3819 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3820 }
3821 if ((tmp == NULL) &&
3822 ((pref == XML_CATA_ALLOW_ALL) ||
3823 (pref == XML_CATA_ALLOW_GLOBAL))) {
3824 tmp = xmlCatalogResolveURI(resource);
3825 }
3826
3827 if (tmp != NULL) {
3828 xmlFree(resource);
3829 resource = tmp;
3830 }
3831 }
3832 }
3833
3834 return resource;
3835}
3836
3837#endif
3838
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003839/**
Owen Taylor3473f882001-02-23 17:55:21 +00003840 * xmlDefaultExternalEntityLoader:
3841 * @URL: the URL for the entity to load
3842 * @ID: the System ID for the entity to load
3843 * @ctxt: the context in which the entity is called or NULL
3844 *
3845 * By default we don't load external entitites, yet.
3846 *
3847 * Returns a new allocated xmlParserInputPtr, or NULL.
3848 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003849static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003850xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003851 xmlParserCtxtPtr ctxt)
3852{
Owen Taylor3473f882001-02-23 17:55:21 +00003853 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003854 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003855
Owen Taylor3473f882001-02-23 17:55:21 +00003856#ifdef DEBUG_EXTERNAL_ENTITIES
3857 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003858 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003859#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00003860 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3861 int options = ctxt->options;
3862
3863 ctxt->options -= XML_PARSE_NONET;
3864 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3865 ctxt->options = options;
3866 return(ret);
3867 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003868#ifdef LIBXML_CATALOG_ENABLED
3869 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003870#endif
3871
3872 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003873 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003874
3875 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003876 if (ID == NULL)
3877 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003878 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003879 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003880 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003881 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003882 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003883 xmlFree(resource);
3884 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003885}
3886
3887static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3888 xmlDefaultExternalEntityLoader;
3889
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003890/**
Owen Taylor3473f882001-02-23 17:55:21 +00003891 * xmlSetExternalEntityLoader:
3892 * @f: the new entity resolver function
3893 *
3894 * Changes the defaultexternal entity resolver function for the application
3895 */
3896void
3897xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3898 xmlCurrentExternalEntityLoader = f;
3899}
3900
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003901/**
Owen Taylor3473f882001-02-23 17:55:21 +00003902 * xmlGetExternalEntityLoader:
3903 *
3904 * Get the default external entity resolver function for the application
3905 *
3906 * Returns the xmlExternalEntityLoader function pointer
3907 */
3908xmlExternalEntityLoader
3909xmlGetExternalEntityLoader(void) {
3910 return(xmlCurrentExternalEntityLoader);
3911}
3912
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003913/**
Owen Taylor3473f882001-02-23 17:55:21 +00003914 * xmlLoadExternalEntity:
3915 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003916 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003917 * @ctxt: the context in which the entity is called or NULL
3918 *
3919 * Load an external entity, note that the use of this function for
3920 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003921 *
3922 * Returns the xmlParserInputPtr or NULL
3923 */
3924xmlParserInputPtr
3925xmlLoadExternalEntity(const char *URL, const char *ID,
3926 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003927 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003928 char *canonicFilename;
3929 xmlParserInputPtr ret;
3930
3931 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3932 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003933 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003934 return(NULL);
3935 }
3936
3937 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3938 xmlFree(canonicFilename);
3939 return(ret);
3940 }
Owen Taylor3473f882001-02-23 17:55:21 +00003941 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3942}
3943
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003944/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003945 * *
3946 * Disabling Network access *
3947 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003948 ************************************************************************/
3949
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003950/**
3951 * xmlNoNetExternalEntityLoader:
3952 * @URL: the URL for the entity to load
3953 * @ID: the System ID for the entity to load
3954 * @ctxt: the context in which the entity is called or NULL
3955 *
3956 * A specific entity loader disabling network accesses, though still
3957 * allowing local catalog accesses for resolution.
3958 *
3959 * Returns a new allocated xmlParserInputPtr, or NULL.
3960 */
3961xmlParserInputPtr
3962xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3963 xmlParserCtxtPtr ctxt) {
3964 xmlParserInputPtr input = NULL;
3965 xmlChar *resource = NULL;
3966
3967#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00003968 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003969#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00003970
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003971 if (resource == NULL)
3972 resource = (xmlChar *) URL;
3973
3974 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003975 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3976 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003977 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003978 if (resource != (xmlChar *) URL)
3979 xmlFree(resource);
3980 return(NULL);
3981 }
3982 }
3983 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3984 if (resource != (xmlChar *) URL)
3985 xmlFree(resource);
3986 return(input);
3987}
3988
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003989#define bottom_xmlIO
3990#include "elfgcchack.h"