blob: 154fcf8699b427d1c86df2ddc6cb291053367a3e [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 Veillarda9cce9c2003-09-29 13:20:24 +0000138#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000139
Daniel Veillard05d987b2003-10-08 11:54:57 +0000140/************************************************************************
141 * *
142 * Tree memory error handler *
143 * *
144 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000145
Daniel Veillard05d987b2003-10-08 11:54:57 +0000146static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000147 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000148 "Permission denied", /* EACCES */
149 "Resource temporarily unavailable",/* EAGAIN */
150 "Bad file descriptor", /* EBADF */
151 "Bad message", /* EBADMSG */
152 "Resource busy", /* EBUSY */
153 "Operation canceled", /* ECANCELED */
154 "No child processes", /* ECHILD */
155 "Resource deadlock avoided",/* EDEADLK */
156 "Domain error", /* EDOM */
157 "File exists", /* EEXIST */
158 "Bad address", /* EFAULT */
159 "File too large", /* EFBIG */
160 "Operation in progress", /* EINPROGRESS */
161 "Interrupted function call",/* EINTR */
162 "Invalid argument", /* EINVAL */
163 "Input/output error", /* EIO */
164 "Is a directory", /* EISDIR */
165 "Too many open files", /* EMFILE */
166 "Too many links", /* EMLINK */
167 "Inappropriate message buffer length",/* EMSGSIZE */
168 "Filename too long", /* ENAMETOOLONG */
169 "Too many open files in system",/* ENFILE */
170 "No such device", /* ENODEV */
171 "No such file or directory",/* ENOENT */
172 "Exec format error", /* ENOEXEC */
173 "No locks available", /* ENOLCK */
174 "Not enough space", /* ENOMEM */
175 "No space left on device", /* ENOSPC */
176 "Function not implemented", /* ENOSYS */
177 "Not a directory", /* ENOTDIR */
178 "Directory not empty", /* ENOTEMPTY */
179 "Not supported", /* ENOTSUP */
180 "Inappropriate I/O control operation",/* ENOTTY */
181 "No such device or address",/* ENXIO */
182 "Operation not permitted", /* EPERM */
183 "Broken pipe", /* EPIPE */
184 "Result too large", /* ERANGE */
185 "Read-only file system", /* EROFS */
186 "Invalid seek", /* ESPIPE */
187 "No such process", /* ESRCH */
188 "Operation timed out", /* ETIMEDOUT */
189 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000190 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000191 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000192 "flush error",
193 "write error",
194 "no input",
195 "buffer full",
196 "loading error",
197 "not a socket", /* ENOTSOCK */
198 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000199 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000200 "unreachable network", /* ENETUNREACH */
201 "adddress in use", /* EADDRINUSE */
202 "already in use", /* EALREADY */
203 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000204};
205
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000206#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000207/**
208 * __xmlIOWin32UTF8ToWChar:
209 * @u8String: uft-8 string
210 *
211 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
212 */
213static wchar_t *
214__xmlIOWin32UTF8ToWChar(const char *u8String)
215{
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000216 wchar_t *wString = NULL;
Daniel Veillardf7416012006-04-27 08:15:20 +0000217
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000218 if (u8String) {
219 int wLen =
220 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
221 -1, NULL, 0);
222 if (wLen) {
223 wString = xmlMalloc(wLen * sizeof(wchar_t));
224 if (wString) {
225 if (MultiByteToWideChar
226 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
227 xmlFree(wString);
228 wString = NULL;
229 }
230 }
231 }
232 }
233
234 return wString;
Daniel Veillardf7416012006-04-27 08:15:20 +0000235}
236#endif
237
Daniel Veillard05d987b2003-10-08 11:54:57 +0000238/**
239 * xmlIOErrMemory:
240 * @extra: extra informations
241 *
242 * Handle an out of memory condition
243 */
244static void
245xmlIOErrMemory(const char *extra)
246{
247 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
248}
249
250/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000251 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000252 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000253 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000254 * @extra: extra informations
255 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000256 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000257 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000258void
259__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000260{
261 unsigned int idx;
262
263 if (code == 0) {
264#ifdef HAVE_ERRNO_H
265 if (errno == 0) code = 0;
266#ifdef EACCES
267 else if (errno == EACCES) code = XML_IO_EACCES;
268#endif
269#ifdef EAGAIN
270 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
271#endif
272#ifdef EBADF
273 else if (errno == EBADF) code = XML_IO_EBADF;
274#endif
275#ifdef EBADMSG
276 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
277#endif
278#ifdef EBUSY
279 else if (errno == EBUSY) code = XML_IO_EBUSY;
280#endif
281#ifdef ECANCELED
282 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
283#endif
284#ifdef ECHILD
285 else if (errno == ECHILD) code = XML_IO_ECHILD;
286#endif
287#ifdef EDEADLK
288 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
289#endif
290#ifdef EDOM
291 else if (errno == EDOM) code = XML_IO_EDOM;
292#endif
293#ifdef EEXIST
294 else if (errno == EEXIST) code = XML_IO_EEXIST;
295#endif
296#ifdef EFAULT
297 else if (errno == EFAULT) code = XML_IO_EFAULT;
298#endif
299#ifdef EFBIG
300 else if (errno == EFBIG) code = XML_IO_EFBIG;
301#endif
302#ifdef EINPROGRESS
303 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
304#endif
305#ifdef EINTR
306 else if (errno == EINTR) code = XML_IO_EINTR;
307#endif
308#ifdef EINVAL
309 else if (errno == EINVAL) code = XML_IO_EINVAL;
310#endif
311#ifdef EIO
312 else if (errno == EIO) code = XML_IO_EIO;
313#endif
314#ifdef EISDIR
315 else if (errno == EISDIR) code = XML_IO_EISDIR;
316#endif
317#ifdef EMFILE
318 else if (errno == EMFILE) code = XML_IO_EMFILE;
319#endif
320#ifdef EMLINK
321 else if (errno == EMLINK) code = XML_IO_EMLINK;
322#endif
323#ifdef EMSGSIZE
324 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
325#endif
326#ifdef ENAMETOOLONG
327 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
328#endif
329#ifdef ENFILE
330 else if (errno == ENFILE) code = XML_IO_ENFILE;
331#endif
332#ifdef ENODEV
333 else if (errno == ENODEV) code = XML_IO_ENODEV;
334#endif
335#ifdef ENOENT
336 else if (errno == ENOENT) code = XML_IO_ENOENT;
337#endif
338#ifdef ENOEXEC
339 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
340#endif
341#ifdef ENOLCK
342 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
343#endif
344#ifdef ENOMEM
345 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
346#endif
347#ifdef ENOSPC
348 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
349#endif
350#ifdef ENOSYS
351 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
352#endif
353#ifdef ENOTDIR
354 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
355#endif
356#ifdef ENOTEMPTY
357 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
358#endif
359#ifdef ENOTSUP
360 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
361#endif
362#ifdef ENOTTY
363 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
364#endif
365#ifdef ENXIO
366 else if (errno == ENXIO) code = XML_IO_ENXIO;
367#endif
368#ifdef EPERM
369 else if (errno == EPERM) code = XML_IO_EPERM;
370#endif
371#ifdef EPIPE
372 else if (errno == EPIPE) code = XML_IO_EPIPE;
373#endif
374#ifdef ERANGE
375 else if (errno == ERANGE) code = XML_IO_ERANGE;
376#endif
377#ifdef EROFS
378 else if (errno == EROFS) code = XML_IO_EROFS;
379#endif
380#ifdef ESPIPE
381 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
382#endif
383#ifdef ESRCH
384 else if (errno == ESRCH) code = XML_IO_ESRCH;
385#endif
386#ifdef ETIMEDOUT
387 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
388#endif
389#ifdef EXDEV
390 else if (errno == EXDEV) code = XML_IO_EXDEV;
391#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000392#ifdef ENOTSOCK
393 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
394#endif
395#ifdef EISCONN
396 else if (errno == EISCONN) code = XML_IO_EISCONN;
397#endif
398#ifdef ECONNREFUSED
399 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
400#endif
401#ifdef ETIMEDOUT
402 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
403#endif
404#ifdef ENETUNREACH
405 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
406#endif
407#ifdef EADDRINUSE
408 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
409#endif
410#ifdef EINPROGRESS
411 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
412#endif
413#ifdef EALREADY
414 else if (errno == EALREADY) code = XML_IO_EALREADY;
415#endif
416#ifdef EAFNOSUPPORT
417 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
418#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000419 else code = XML_IO_UNKNOWN;
420#endif /* HAVE_ERRNO_H */
421 }
422 idx = 0;
423 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
424 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
425
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000426 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
427}
428
429/**
430 * xmlIOErr:
431 * @code: the error number
432 * @extra: extra informations
433 *
434 * Handle an I/O error
435 */
436static void
437xmlIOErr(int code, const char *extra)
438{
439 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000440}
441
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000442/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000443 * __xmlLoaderErr:
444 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000445 * @extra: extra informations
446 *
447 * Handle a resource access error
448 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000449void
450__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000451{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000452 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000453 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000454 xmlGenericErrorFunc channel = NULL;
455 void *data = NULL;
456 xmlErrorLevel level = XML_ERR_ERROR;
457
Daniel Veillard157fee02003-10-31 10:36:03 +0000458 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
459 (ctxt->instate == XML_PARSER_EOF))
460 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000461 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
462 if (ctxt->validate) {
463 channel = ctxt->sax->error;
464 level = XML_ERR_ERROR;
465 } else {
466 channel = ctxt->sax->warning;
467 level = XML_ERR_WARNING;
468 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000469 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
470 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000471 data = ctxt->userData;
472 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000473 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000474 XML_IO_LOAD_ERROR, level, NULL, 0,
475 filename, NULL, NULL, 0, 0,
476 msg, filename);
477
478}
479
Daniel Veillard05d987b2003-10-08 11:54:57 +0000480/************************************************************************
481 * *
482 * Tree memory error handler *
483 * *
484 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000485/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000486 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000487 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000488 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000489 * This function is obsolete. Please see xmlURIFromPath in uri.c for
490 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000491 *
492 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000493 */
494xmlChar *
495xmlNormalizeWindowsPath(const xmlChar *path)
496{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000497 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000498}
499
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000500/**
501 * xmlCleanupInputCallbacks:
502 *
503 * clears the entire input callback table. this includes the
504 * compiled-in I/O.
505 */
506void
507xmlCleanupInputCallbacks(void)
508{
509 int i;
510
511 if (!xmlInputCallbackInitialized)
512 return;
513
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000514 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000515 xmlInputCallbackTable[i].matchcallback = NULL;
516 xmlInputCallbackTable[i].opencallback = NULL;
517 xmlInputCallbackTable[i].readcallback = NULL;
518 xmlInputCallbackTable[i].closecallback = NULL;
519 }
520
521 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000522 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000523}
524
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000525/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000526 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000527 *
528 * Clear the top input callback from the input stack. this includes the
529 * compiled-in I/O.
530 *
531 * Returns the number of input callback registered or -1 in case of error.
532 */
533int
534xmlPopInputCallbacks(void)
535{
536 if (!xmlInputCallbackInitialized)
537 return(-1);
538
539 if (xmlInputCallbackNr <= 0)
540 return(-1);
541
542 xmlInputCallbackNr--;
543 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
544 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
545 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
546 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
547
548 return(xmlInputCallbackNr);
549}
550
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000551#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000552/**
553 * xmlCleanupOutputCallbacks:
554 *
555 * clears the entire output callback table. this includes the
556 * compiled-in I/O callbacks.
557 */
558void
559xmlCleanupOutputCallbacks(void)
560{
561 int i;
562
563 if (!xmlOutputCallbackInitialized)
564 return;
565
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000566 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000567 xmlOutputCallbackTable[i].matchcallback = NULL;
568 xmlOutputCallbackTable[i].opencallback = NULL;
569 xmlOutputCallbackTable[i].writecallback = NULL;
570 xmlOutputCallbackTable[i].closecallback = NULL;
571 }
572
573 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000574 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000575}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000576#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000577
Owen Taylor3473f882001-02-23 17:55:21 +0000578/************************************************************************
579 * *
580 * Standard I/O for file accesses *
581 * *
582 ************************************************************************/
583
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000584#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
585
586/**
587 * xmlWrapOpenUtf8:
588 * @path: the path in utf-8 encoding
589 * @mode: type of access (0 - read, 1 - write)
590 *
591 * function opens the file specified by @path
592 *
593 */
594static FILE*
595xmlWrapOpenUtf8(const char *path,int mode)
596{
597 FILE *fd = NULL;
598 wchar_t *wPath;
599
600 wPath = __xmlIOWin32UTF8ToWChar(path);
601 if(wPath)
602 {
603 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
604 xmlFree(wPath);
605 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000606 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000607 if(fd == NULL)
608 fd = fopen(path, mode ? "wb" : "rb");
609
610 return fd;
611}
612
613/**
614 * xmlWrapStatUtf8:
615 * @path: the path in utf-8 encoding
616 * @info: structure that stores results
617 *
618 * function obtains information about the file or directory
619 *
620 */
621static int
622xmlWrapStatUtf8(const char *path,struct stat *info)
623{
624#ifdef HAVE_STAT
625 int retval = -1;
626 wchar_t *wPath;
627
628 wPath = __xmlIOWin32UTF8ToWChar(path);
629 if (wPath)
630 {
631 retval = _wstat(wPath,info);
632 xmlFree(wPath);
633 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000634 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000635 if(retval < 0)
636 retval = stat(path,info);
637 return retval;
638#else
639 return -1;
640#endif
641}
642
643/**
644 * xmlWrapOpenNative:
645 * @path: the path
646 * @mode: type of access (0 - read, 1 - write)
647 *
648 * function opens the file specified by @path
649 *
650 */
651static FILE*
652xmlWrapOpenNative(const char *path,int mode)
653{
654 return fopen(path,mode ? "wb" : "rb");
655}
656
657/**
658 * xmlWrapStatNative:
659 * @path: the path
660 * @info: structure that stores results
661 *
662 * function obtains information about the file or directory
663 *
664 */
665static int
666xmlWrapStatNative(const char *path,struct stat *info)
667{
668#ifdef HAVE_STAT
669 return stat(path,info);
670#else
671 return -1;
672#endif
673}
674
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000675typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
676static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
677typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
Rob Richards6460f922006-10-12 21:08:29 +0000678static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000679
680/**
681 * xmlInitPlatformSpecificIo:
682 *
683 * Initialize platform specific features.
684 */
685static void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000686xmlInitPlatformSpecificIo(void)
687{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000688 static int xmlPlatformIoInitialized = 0;
689 OSVERSIONINFO osvi;
690
691 if(xmlPlatformIoInitialized)
692 return;
693
694 osvi.dwOSVersionInfoSize = sizeof(osvi);
695
696 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
697 xmlWrapStat = xmlWrapStatUtf8;
698 xmlWrapOpen = xmlWrapOpenUtf8;
699 } else {
700 xmlWrapStat = xmlWrapStatNative;
701 xmlWrapOpen = xmlWrapOpenNative;
702 }
703
704 xmlPlatformIoInitialized = 1;
705 return;
706}
707
708#endif
709
Owen Taylor3473f882001-02-23 17:55:21 +0000710/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000711 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000712 * @path: the path to check
713 *
714 * function checks to see if @path is a valid source
715 * (file, socket...) for XML.
716 *
717 * if stat is not available on the target machine,
718 * returns 1. if stat fails, returns 0 (if calling
719 * stat on the filename fails, it can't be right).
720 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000721 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000722 */
723
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000724int
Owen Taylor3473f882001-02-23 17:55:21 +0000725xmlCheckFilename (const char *path)
726{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000727#ifdef HAVE_STAT
Daniel Veillard0b309952006-05-02 20:34:38 +0000728 struct stat stat_buffer;
729#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000730 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000731 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000732
Owen Taylor3473f882001-02-23 17:55:21 +0000733#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000734#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
735 if (xmlWrapStat(path, &stat_buffer) == -1)
736 return 0;
737#else
Owen Taylor3473f882001-02-23 17:55:21 +0000738 if (stat(path, &stat_buffer) == -1)
739 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000740#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000741#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000742 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000743 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000744#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000745#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000746 return 1;
747}
748
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000749static int
Owen Taylor3473f882001-02-23 17:55:21 +0000750xmlNop(void) {
751 return(0);
752}
753
754/**
Owen Taylor3473f882001-02-23 17:55:21 +0000755 * xmlFdRead:
756 * @context: the I/O context
757 * @buffer: where to drop data
758 * @len: number of bytes to read
759 *
760 * Read @len bytes to @buffer from the I/O channel.
761 *
762 * Returns the number of bytes written
763 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000764static int
Owen Taylor3473f882001-02-23 17:55:21 +0000765xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000766 int ret;
767
768 ret = read((int) (long) context, &buffer[0], len);
769 if (ret < 0) xmlIOErr(0, "read()");
770 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000771}
772
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000773#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000774/**
775 * xmlFdWrite:
776 * @context: the I/O context
777 * @buffer: where to get data
778 * @len: number of bytes to write
779 *
780 * Write @len bytes from @buffer to the I/O channel.
781 *
782 * Returns the number of bytes written
783 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000784static int
Owen Taylor3473f882001-02-23 17:55:21 +0000785xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000786 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000787
Daniel Veillard9b693b42005-10-28 14:54:17 +0000788 if (len > 0) {
789 ret = write((int) (long) context, &buffer[0], len);
790 if (ret < 0) xmlIOErr(0, "write()");
791 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000792 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000793}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000794#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000795
796/**
797 * xmlFdClose:
798 * @context: the I/O context
799 *
800 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000801 *
802 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000803 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000804static int
Owen Taylor3473f882001-02-23 17:55:21 +0000805xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000806 int ret;
807 ret = close((int) (long) context);
808 if (ret < 0) xmlIOErr(0, "close()");
809 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000810}
811
812/**
813 * xmlFileMatch:
814 * @filename: the URI for matching
815 *
816 * input from FILE *
817 *
818 * Returns 1 if matches, 0 otherwise
819 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000820int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000821xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000822 return(1);
823}
824
825/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000826 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000827 * @filename: the URI for matching
828 *
829 * input from FILE *, supports compressed input
830 * if @filename is " " then the standard input is used
831 *
832 * Returns an I/O context or NULL in case of error
833 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000834static void *
835xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000836 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000837 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000838
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000839 if (filename == NULL)
840 return(NULL);
841
Owen Taylor3473f882001-02-23 17:55:21 +0000842 if (!strcmp(filename, "-")) {
843 fd = stdin;
844 return((void *) fd);
845 }
846
Daniel Veillardf4862f02002-09-10 11:13:43 +0000847 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000848#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000849 path = &filename[17];
850#else
Owen Taylor3473f882001-02-23 17:55:21 +0000851 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000852#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000853 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000854#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000855 path = &filename[8];
856#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000857 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000858#endif
859 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000860 path = filename;
861
862 if (path == NULL)
863 return(NULL);
864 if (!xmlCheckFilename(path))
865 return(NULL);
866
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000867#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
868 fd = xmlWrapOpen(path, 0);
869#else
870 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000871#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000872 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000873 return((void *) fd);
874}
875
876/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000877 * xmlFileOpen:
878 * @filename: the URI for matching
879 *
880 * Wrapper around xmlFileOpen_real that try it with an unescaped
881 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000882 *
883 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000884 */
885void *
886xmlFileOpen (const char *filename) {
887 char *unescaped;
888 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000889
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000890 retval = xmlFileOpen_real(filename);
891 if (retval == NULL) {
892 unescaped = xmlURIUnescapeString(filename, 0, NULL);
893 if (unescaped != NULL) {
894 retval = xmlFileOpen_real(unescaped);
895 xmlFree(unescaped);
896 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000897 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000898
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000899 return retval;
900}
901
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000902#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000903/**
Owen Taylor3473f882001-02-23 17:55:21 +0000904 * xmlFileOpenW:
905 * @filename: the URI for matching
906 *
907 * output to from FILE *,
908 * if @filename is "-" then the standard output is used
909 *
910 * Returns an I/O context or NULL in case of error
911 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000912static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000913xmlFileOpenW (const char *filename) {
914 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000915 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000916
917 if (!strcmp(filename, "-")) {
918 fd = stdout;
919 return((void *) fd);
920 }
921
Daniel Veillardf4862f02002-09-10 11:13:43 +0000922 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000923#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000924 path = &filename[17];
925#else
Owen Taylor3473f882001-02-23 17:55:21 +0000926 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000927#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000928 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000929#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000930 path = &filename[8];
931#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000932 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000933#endif
934 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000935 path = filename;
936
937 if (path == NULL)
938 return(NULL);
939
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000940#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
941 fd = xmlWrapOpen(path, 1);
942#else
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000943 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000944#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000945
Daniel Veillardf7416012006-04-27 08:15:20 +0000946 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000947 return((void *) fd);
948}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000949#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000950
951/**
952 * xmlFileRead:
953 * @context: the I/O context
954 * @buffer: where to drop data
955 * @len: number of bytes to write
956 *
957 * Read @len bytes to @buffer from the I/O channel.
958 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000959 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000960 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000961int
Owen Taylor3473f882001-02-23 17:55:21 +0000962xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000963 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000964 if ((context == NULL) || (buffer == NULL))
965 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000966 ret = fread(&buffer[0], 1, len, (FILE *) context);
967 if (ret < 0) xmlIOErr(0, "fread()");
968 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000969}
970
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000971#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000972/**
973 * xmlFileWrite:
974 * @context: the I/O context
975 * @buffer: where to drop data
976 * @len: number of bytes to write
977 *
978 * Write @len bytes from @buffer to the I/O channel.
979 *
980 * Returns the number of bytes written
981 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000982static int
Owen Taylor3473f882001-02-23 17:55:21 +0000983xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000984 int items;
985
Daniel Veillardce682bc2004-11-05 17:22:25 +0000986 if ((context == NULL) || (buffer == NULL))
987 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000988 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000989 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000990 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000991 return(-1);
992 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000993 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000994}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000995#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000996
997/**
998 * xmlFileClose:
999 * @context: the I/O context
1000 *
1001 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001002 *
1003 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001004 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001005int
Owen Taylor3473f882001-02-23 17:55:21 +00001006xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001007 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001008 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001009
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001010 if (context == NULL)
1011 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001012 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001013 if ((fil == stdout) || (fil == stderr)) {
1014 ret = fflush(fil);
1015 if (ret < 0)
1016 xmlIOErr(0, "fflush()");
1017 return(0);
1018 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001019 if (fil == stdin)
1020 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001021 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1022 if (ret < 0)
1023 xmlIOErr(0, "fclose()");
1024 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001025}
1026
1027/**
1028 * xmlFileFlush:
1029 * @context: the I/O context
1030 *
1031 * Flush an I/O channel
1032 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001033static int
Owen Taylor3473f882001-02-23 17:55:21 +00001034xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001035 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001036
1037 if (context == NULL)
1038 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001039 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1040 if (ret < 0)
1041 xmlIOErr(0, "fflush()");
1042 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001043}
1044
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001045#ifdef LIBXML_OUTPUT_ENABLED
1046/**
1047 * xmlBufferWrite:
1048 * @context: the xmlBuffer
1049 * @buffer: the data to write
1050 * @len: number of bytes to write
1051 *
1052 * Write @len bytes from @buffer to the xml buffer
1053 *
1054 * Returns the number of bytes written
1055 */
1056static int
1057xmlBufferWrite (void * context, const char * buffer, int len) {
1058 int ret;
1059
1060 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1061 if (ret != 0)
1062 return(-1);
1063 return(len);
1064}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001065#endif
1066
Owen Taylor3473f882001-02-23 17:55:21 +00001067#ifdef HAVE_ZLIB_H
1068/************************************************************************
1069 * *
1070 * I/O for compressed file accesses *
1071 * *
1072 ************************************************************************/
1073/**
1074 * xmlGzfileMatch:
1075 * @filename: the URI for matching
1076 *
1077 * input from compressed file test
1078 *
1079 * Returns 1 if matches, 0 otherwise
1080 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001081static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001082xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001083 return(1);
1084}
1085
1086/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001087 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001088 * @filename: the URI for matching
1089 *
1090 * input from compressed file open
1091 * if @filename is " " then the standard input is used
1092 *
1093 * Returns an I/O context or NULL in case of error
1094 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001095static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001096xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001097 const char *path = NULL;
1098 gzFile fd;
1099
1100 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001101 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001102 return((void *) fd);
1103 }
1104
Daniel Veillardf4862f02002-09-10 11:13:43 +00001105 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001106#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001107 path = &filename[17];
1108#else
Owen Taylor3473f882001-02-23 17:55:21 +00001109 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001110#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001111 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001112#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001113 path = &filename[8];
1114#else
Owen Taylor3473f882001-02-23 17:55:21 +00001115 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001116#endif
1117 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001118 path = filename;
1119
1120 if (path == NULL)
1121 return(NULL);
1122 if (!xmlCheckFilename(path))
1123 return(NULL);
1124
1125 fd = gzopen(path, "rb");
1126 return((void *) fd);
1127}
1128
1129/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001130 * xmlGzfileOpen:
1131 * @filename: the URI for matching
1132 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001133 * Wrapper around xmlGzfileOpen if the open fais, it will
1134 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001135 */
1136static void *
1137xmlGzfileOpen (const char *filename) {
1138 char *unescaped;
1139 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001140
1141 retval = xmlGzfileOpen_real(filename);
1142 if (retval == NULL) {
1143 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1144 if (unescaped != NULL) {
1145 retval = xmlGzfileOpen_real(unescaped);
1146 }
1147 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001148 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001149 return retval;
1150}
1151
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001152#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001153/**
Owen Taylor3473f882001-02-23 17:55:21 +00001154 * xmlGzfileOpenW:
1155 * @filename: the URI for matching
1156 * @compression: the compression factor (0 - 9 included)
1157 *
1158 * input from compressed file open
1159 * if @filename is " " then the standard input is used
1160 *
1161 * Returns an I/O context or NULL in case of error
1162 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001163static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001164xmlGzfileOpenW (const char *filename, int compression) {
1165 const char *path = NULL;
1166 char mode[15];
1167 gzFile fd;
1168
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001169 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001170 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001171 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001172 return((void *) fd);
1173 }
1174
Daniel Veillardf4862f02002-09-10 11:13:43 +00001175 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001176#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001177 path = &filename[17];
1178#else
Owen Taylor3473f882001-02-23 17:55:21 +00001179 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001180#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001181 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001182#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001183 path = &filename[8];
1184#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001185 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001186#endif
1187 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001188 path = filename;
1189
1190 if (path == NULL)
1191 return(NULL);
1192
1193 fd = gzopen(path, mode);
1194 return((void *) fd);
1195}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001196#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001197
1198/**
1199 * xmlGzfileRead:
1200 * @context: the I/O context
1201 * @buffer: where to drop data
1202 * @len: number of bytes to write
1203 *
1204 * Read @len bytes to @buffer from the compressed I/O channel.
1205 *
1206 * Returns the number of bytes written
1207 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001208static int
Owen Taylor3473f882001-02-23 17:55:21 +00001209xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001210 int ret;
1211
1212 ret = gzread((gzFile) context, &buffer[0], len);
1213 if (ret < 0) xmlIOErr(0, "gzread()");
1214 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001215}
1216
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001217#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001218/**
1219 * xmlGzfileWrite:
1220 * @context: the I/O context
1221 * @buffer: where to drop data
1222 * @len: number of bytes to write
1223 *
1224 * Write @len bytes from @buffer to the compressed I/O channel.
1225 *
1226 * Returns the number of bytes written
1227 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001228static int
Owen Taylor3473f882001-02-23 17:55:21 +00001229xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001230 int ret;
1231
1232 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1233 if (ret < 0) xmlIOErr(0, "gzwrite()");
1234 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001235}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001236#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001237
1238/**
1239 * xmlGzfileClose:
1240 * @context: the I/O context
1241 *
1242 * Close a compressed I/O channel
1243 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001244static int
Owen Taylor3473f882001-02-23 17:55:21 +00001245xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001246 int ret;
1247
1248 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1249 if (ret < 0) xmlIOErr(0, "gzclose()");
1250 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001251}
1252#endif /* HAVE_ZLIB_H */
1253
1254#ifdef LIBXML_HTTP_ENABLED
1255/************************************************************************
1256 * *
1257 * I/O for HTTP file accesses *
1258 * *
1259 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001260
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001261#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001262typedef struct xmlIOHTTPWriteCtxt_
1263{
1264 int compression;
1265
1266 char * uri;
1267
1268 void * doc_buff;
1269
1270} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1271
1272#ifdef HAVE_ZLIB_H
1273
1274#define DFLT_WBITS ( -15 )
1275#define DFLT_MEM_LVL ( 8 )
1276#define GZ_MAGIC1 ( 0x1f )
1277#define GZ_MAGIC2 ( 0x8b )
1278#define LXML_ZLIB_OS_CODE ( 0x03 )
1279#define INIT_HTTP_BUFF_SIZE ( 32768 )
1280#define DFLT_ZLIB_RATIO ( 5 )
1281
1282/*
1283** Data structure and functions to work with sending compressed data
1284** via HTTP.
1285*/
1286
1287typedef struct xmlZMemBuff_
1288{
1289 unsigned long size;
1290 unsigned long crc;
1291
1292 unsigned char * zbuff;
1293 z_stream zctrl;
1294
1295} xmlZMemBuff, *xmlZMemBuffPtr;
1296
1297/**
1298 * append_reverse_ulong
1299 * @buff: Compressed memory buffer
1300 * @data: Unsigned long to append
1301 *
1302 * Append a unsigned long in reverse byte order to the end of the
1303 * memory buffer.
1304 */
1305static void
1306append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1307
1308 int idx;
1309
1310 if ( buff == NULL )
1311 return;
1312
1313 /*
1314 ** This is plagiarized from putLong in gzio.c (zlib source) where
1315 ** the number "4" is hardcoded. If zlib is ever patched to
1316 ** support 64 bit file sizes, this code would need to be patched
1317 ** as well.
1318 */
1319
1320 for ( idx = 0; idx < 4; idx++ ) {
1321 *buff->zctrl.next_out = ( data & 0xff );
1322 data >>= 8;
1323 buff->zctrl.next_out++;
1324 }
1325
1326 return;
1327}
1328
1329/**
1330 *
1331 * xmlFreeZMemBuff
1332 * @buff: The memory buffer context to clear
1333 *
1334 * Release all the resources associated with the compressed memory buffer.
1335 */
1336static void
1337xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001338
1339#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001340 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001341#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001342
1343 if ( buff == NULL )
1344 return;
1345
1346 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001347#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001348 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001349 if ( z_err != Z_OK )
1350 xmlGenericError( xmlGenericErrorContext,
1351 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1352 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001353#else
1354 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001355#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001356
1357 xmlFree( buff );
1358 return;
1359}
1360
1361/**
1362 * xmlCreateZMemBuff
1363 *@compression: Compression value to use
1364 *
1365 * Create a memory buffer to hold the compressed XML document. The
1366 * compressed document in memory will end up being identical to what
1367 * would be created if gzopen/gzwrite/gzclose were being used to
1368 * write the document to disk. The code for the header/trailer data to
1369 * the compression is plagiarized from the zlib source files.
1370 */
1371static void *
1372xmlCreateZMemBuff( int compression ) {
1373
1374 int z_err;
1375 int hdr_lgth;
1376 xmlZMemBuffPtr buff = NULL;
1377
1378 if ( ( compression < 1 ) || ( compression > 9 ) )
1379 return ( NULL );
1380
1381 /* Create the control and data areas */
1382
1383 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1384 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001385 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001386 return ( NULL );
1387 }
1388
1389 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1390 buff->size = INIT_HTTP_BUFF_SIZE;
1391 buff->zbuff = xmlMalloc( buff->size );
1392 if ( buff->zbuff == NULL ) {
1393 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001394 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001395 return ( NULL );
1396 }
1397
1398 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1399 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1400 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001401 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001402 xmlFreeZMemBuff( buff );
1403 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001404 xmlStrPrintf(msg, 500,
1405 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1406 "Error initializing compression context. ZLIB error:",
1407 z_err );
1408 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001409 return ( NULL );
1410 }
1411
1412 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001413 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001414 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1415 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001416 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1417 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1418 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1419 buff->zctrl.avail_out = buff->size - hdr_lgth;
1420
1421 return ( buff );
1422}
1423
1424/**
1425 * xmlZMemBuffExtend
1426 * @buff: Buffer used to compress and consolidate data.
1427 * @ext_amt: Number of bytes to extend the buffer.
1428 *
1429 * Extend the internal buffer used to store the compressed data by the
1430 * specified amount.
1431 *
1432 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1433 * the original buffer still exists at the original size.
1434 */
1435static int
1436xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1437
1438 int rc = -1;
1439 size_t new_size;
1440 size_t cur_used;
1441
1442 unsigned char * tmp_ptr = NULL;
1443
1444 if ( buff == NULL )
1445 return ( -1 );
1446
1447 else if ( ext_amt == 0 )
1448 return ( 0 );
1449
1450 cur_used = buff->zctrl.next_out - buff->zbuff;
1451 new_size = buff->size + ext_amt;
1452
1453#ifdef DEBUG_HTTP
1454 if ( cur_used > new_size )
1455 xmlGenericError( xmlGenericErrorContext,
1456 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1457 "Buffer overwrite detected during compressed memory",
1458 "buffer extension. Overflowed by",
1459 (cur_used - new_size ) );
1460#endif
1461
1462 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1463 if ( tmp_ptr != NULL ) {
1464 rc = 0;
1465 buff->size = new_size;
1466 buff->zbuff = tmp_ptr;
1467 buff->zctrl.next_out = tmp_ptr + cur_used;
1468 buff->zctrl.avail_out = new_size - cur_used;
1469 }
1470 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001471 xmlChar msg[500];
1472 xmlStrPrintf(msg, 500,
1473 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1474 "Allocation failure extending output buffer to",
1475 new_size );
1476 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001477 }
1478
1479 return ( rc );
1480}
1481
1482/**
1483 * xmlZMemBuffAppend
1484 * @buff: Buffer used to compress and consolidate data
1485 * @src: Uncompressed source content to append to buffer
1486 * @len: Length of source data to append to buffer
1487 *
1488 * Compress and append data to the internal buffer. The data buffer
1489 * will be expanded if needed to store the additional data.
1490 *
1491 * Returns the number of bytes appended to the buffer or -1 on error.
1492 */
1493static int
1494xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1495
1496 int z_err;
1497 size_t min_accept;
1498
1499 if ( ( buff == NULL ) || ( src == NULL ) )
1500 return ( -1 );
1501
1502 buff->zctrl.avail_in = len;
1503 buff->zctrl.next_in = (unsigned char *)src;
1504 while ( buff->zctrl.avail_in > 0 ) {
1505 /*
1506 ** Extend the buffer prior to deflate call if a reasonable amount
1507 ** of output buffer space is not available.
1508 */
1509 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1510 if ( buff->zctrl.avail_out <= min_accept ) {
1511 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1512 return ( -1 );
1513 }
1514
1515 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1516 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001517 xmlChar msg[500];
1518 xmlStrPrintf(msg, 500,
1519 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001520 "Compression error while appending",
1521 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001522 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001523 return ( -1 );
1524 }
1525 }
1526
1527 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1528
1529 return ( len );
1530}
1531
1532/**
1533 * xmlZMemBuffGetContent
1534 * @buff: Compressed memory content buffer
1535 * @data_ref: Pointer reference to point to compressed content
1536 *
1537 * Flushes the compression buffers, appends gzip file trailers and
1538 * returns the compressed content and length of the compressed data.
1539 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1540 *
1541 * Returns the length of the compressed data or -1 on error.
1542 */
1543static int
1544xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1545
1546 int zlgth = -1;
1547 int z_err;
1548
1549 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1550 return ( -1 );
1551
1552 /* Need to loop until compression output buffers are flushed */
1553
1554 do
1555 {
1556 z_err = deflate( &buff->zctrl, Z_FINISH );
1557 if ( z_err == Z_OK ) {
1558 /* In this case Z_OK means more buffer space needed */
1559
1560 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1561 return ( -1 );
1562 }
1563 }
1564 while ( z_err == Z_OK );
1565
1566 /* If the compression state is not Z_STREAM_END, some error occurred */
1567
1568 if ( z_err == Z_STREAM_END ) {
1569
1570 /* Need to append the gzip data trailer */
1571
1572 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1573 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1574 return ( -1 );
1575 }
1576
1577 /*
1578 ** For whatever reason, the CRC and length data are pushed out
1579 ** in reverse byte order. So a memcpy can't be used here.
1580 */
1581
1582 append_reverse_ulong( buff, buff->crc );
1583 append_reverse_ulong( buff, buff->zctrl.total_in );
1584
1585 zlgth = buff->zctrl.next_out - buff->zbuff;
1586 *data_ref = (char *)buff->zbuff;
1587 }
1588
Daniel Veillard05d987b2003-10-08 11:54:57 +00001589 else {
1590 xmlChar msg[500];
1591 xmlStrPrintf(msg, 500,
1592 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1593 "Error flushing zlib buffers. Error code", z_err );
1594 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1595 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001596
1597 return ( zlgth );
1598}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001599#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001600#endif /* HAVE_ZLIB_H */
1601
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001602#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001603/**
1604 * xmlFreeHTTPWriteCtxt
1605 * @ctxt: Context to cleanup
1606 *
1607 * Free allocated memory and reclaim system resources.
1608 *
1609 * No return value.
1610 */
1611static void
1612xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1613{
1614 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001615 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001616
1617 if ( ctxt->doc_buff != NULL ) {
1618
1619#ifdef HAVE_ZLIB_H
1620 if ( ctxt->compression > 0 ) {
1621 xmlFreeZMemBuff( ctxt->doc_buff );
1622 }
1623 else
1624#endif
1625 {
1626 xmlOutputBufferClose( ctxt->doc_buff );
1627 }
1628 }
1629
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001630 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001631 return;
1632}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001633#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001634
1635
Owen Taylor3473f882001-02-23 17:55:21 +00001636/**
1637 * xmlIOHTTPMatch:
1638 * @filename: the URI for matching
1639 *
1640 * check if the URI matches an HTTP one
1641 *
1642 * Returns 1 if matches, 0 otherwise
1643 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001644int
Owen Taylor3473f882001-02-23 17:55:21 +00001645xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001646 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001647 return(1);
1648 return(0);
1649}
1650
1651/**
1652 * xmlIOHTTPOpen:
1653 * @filename: the URI for matching
1654 *
1655 * open an HTTP I/O channel
1656 *
1657 * Returns an I/O context or NULL in case of error
1658 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001659void *
Owen Taylor3473f882001-02-23 17:55:21 +00001660xmlIOHTTPOpen (const char *filename) {
1661 return(xmlNanoHTTPOpen(filename, NULL));
1662}
1663
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001664#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001665/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001666 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001667 * @post_uri: The destination URI for the document
1668 * @compression: The compression desired for the document.
1669 *
1670 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1671 * request. Non-static as is called from the output buffer creation routine.
1672 *
1673 * Returns an I/O context or NULL in case of error.
1674 */
1675
1676void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001677xmlIOHTTPOpenW(const char *post_uri, int compression)
1678{
Daniel Veillardf012a642001-07-23 19:10:52 +00001679
Daniel Veillard572577e2002-01-18 16:23:55 +00001680 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001681
Daniel Veillard572577e2002-01-18 16:23:55 +00001682 if (post_uri == NULL)
1683 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001684
Daniel Veillard572577e2002-01-18 16:23:55 +00001685 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1686 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001687 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001688 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001689 }
1690
Daniel Veillard572577e2002-01-18 16:23:55 +00001691 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001692
Daniel Veillard572577e2002-01-18 16:23:55 +00001693 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1694 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001695 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001696 xmlFreeHTTPWriteCtxt(ctxt);
1697 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001698 }
1699
1700 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001701 * ** Since the document length is required for an HTTP post,
1702 * ** need to put the document into a buffer. A memory buffer
1703 * ** is being used to avoid pushing the data to disk and back.
1704 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001705
1706#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001707 if ((compression > 0) && (compression <= 9)) {
1708
1709 ctxt->compression = compression;
1710 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1711 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001712#endif
1713 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001714 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001715
Daniel Veillard572577e2002-01-18 16:23:55 +00001716 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001717 }
1718
Daniel Veillard572577e2002-01-18 16:23:55 +00001719 if (ctxt->doc_buff == NULL) {
1720 xmlFreeHTTPWriteCtxt(ctxt);
1721 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001722 }
1723
Daniel Veillard572577e2002-01-18 16:23:55 +00001724 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001725}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001726#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001727
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001728#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001729/**
1730 * xmlIOHTTPDfltOpenW
1731 * @post_uri: The destination URI for this document.
1732 *
1733 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1734 * HTTP post command. This function should generally not be used as
1735 * the open callback is short circuited in xmlOutputBufferCreateFile.
1736 *
1737 * Returns a pointer to the new IO context.
1738 */
1739static void *
1740xmlIOHTTPDfltOpenW( const char * post_uri ) {
1741 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1742}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001743#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001744
1745/**
Owen Taylor3473f882001-02-23 17:55:21 +00001746 * xmlIOHTTPRead:
1747 * @context: the I/O context
1748 * @buffer: where to drop data
1749 * @len: number of bytes to write
1750 *
1751 * Read @len bytes to @buffer from the I/O channel.
1752 *
1753 * Returns the number of bytes written
1754 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001755int
Owen Taylor3473f882001-02-23 17:55:21 +00001756xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001757 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001758 return(xmlNanoHTTPRead(context, &buffer[0], len));
1759}
1760
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001761#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001762/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001763 * xmlIOHTTPWrite
1764 * @context: previously opened writing context
1765 * @buffer: data to output to temporary buffer
1766 * @len: bytes to output
1767 *
1768 * Collect data from memory buffer into a temporary file for later
1769 * processing.
1770 *
1771 * Returns number of bytes written.
1772 */
1773
1774static int
1775xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1776
1777 xmlIOHTTPWriteCtxtPtr ctxt = context;
1778
1779 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1780 return ( -1 );
1781
1782 if ( len > 0 ) {
1783
1784 /* Use gzwrite or fwrite as previously setup in the open call */
1785
1786#ifdef HAVE_ZLIB_H
1787 if ( ctxt->compression > 0 )
1788 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1789
1790 else
1791#endif
1792 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1793
1794 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001795 xmlChar msg[500];
1796 xmlStrPrintf(msg, 500,
1797 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001798 "Error appending to internal buffer.",
1799 "Error sending document to URI",
1800 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001801 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001802 }
1803 }
1804
1805 return ( len );
1806}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001807#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001808
1809
1810/**
Owen Taylor3473f882001-02-23 17:55:21 +00001811 * xmlIOHTTPClose:
1812 * @context: the I/O context
1813 *
1814 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001815 *
1816 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001817 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001818int
Owen Taylor3473f882001-02-23 17:55:21 +00001819xmlIOHTTPClose (void * context) {
1820 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001821 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001822}
Daniel Veillardf012a642001-07-23 19:10:52 +00001823
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001824#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001825/**
1826 * xmlIOHTTCloseWrite
1827 * @context: The I/O context
1828 * @http_mthd: The HTTP method to be used when sending the data
1829 *
1830 * Close the transmit HTTP I/O channel and actually send the data.
1831 */
1832static int
1833xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1834
1835 int close_rc = -1;
1836 int http_rtn = 0;
1837 int content_lgth = 0;
1838 xmlIOHTTPWriteCtxtPtr ctxt = context;
1839
1840 char * http_content = NULL;
1841 char * content_encoding = NULL;
1842 char * content_type = (char *) "text/xml";
1843 void * http_ctxt = NULL;
1844
1845 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1846 return ( -1 );
1847
1848 /* Retrieve the content from the appropriate buffer */
1849
1850#ifdef HAVE_ZLIB_H
1851
1852 if ( ctxt->compression > 0 ) {
1853 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1854 content_encoding = (char *) "Content-Encoding: gzip";
1855 }
1856 else
1857#endif
1858 {
1859 /* Pull the data out of the memory output buffer */
1860
1861 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1862 http_content = (char *)dctxt->buffer->content;
1863 content_lgth = dctxt->buffer->use;
1864 }
1865
1866 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001867 xmlChar msg[500];
1868 xmlStrPrintf(msg, 500,
1869 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1870 "Error retrieving content.\nUnable to",
1871 http_mthd, "data to URI", ctxt->uri );
1872 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001873 }
1874
1875 else {
1876
1877 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1878 &content_type, content_encoding,
1879 content_lgth );
1880
1881 if ( http_ctxt != NULL ) {
1882#ifdef DEBUG_HTTP
1883 /* If testing/debugging - dump reply with request content */
1884
1885 FILE * tst_file = NULL;
1886 char buffer[ 4096 ];
1887 char * dump_name = NULL;
1888 int avail;
1889
1890 xmlGenericError( xmlGenericErrorContext,
1891 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1892 http_mthd, ctxt->uri,
1893 xmlNanoHTTPReturnCode( http_ctxt ) );
1894
1895 /*
1896 ** Since either content or reply may be gzipped,
1897 ** dump them to separate files instead of the
1898 ** standard error context.
1899 */
1900
1901 dump_name = tempnam( NULL, "lxml" );
1902 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001903 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001904
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001905 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001906 if ( tst_file != NULL ) {
1907 xmlGenericError( xmlGenericErrorContext,
1908 "Transmitted content saved in file: %s\n", buffer );
1909
1910 fwrite( http_content, sizeof( char ),
1911 content_lgth, tst_file );
1912 fclose( tst_file );
1913 }
1914
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001915 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001916 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001917 if ( tst_file != NULL ) {
1918 xmlGenericError( xmlGenericErrorContext,
1919 "Reply content saved in file: %s\n", buffer );
1920
1921
1922 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1923 buffer, sizeof( buffer ) )) > 0 ) {
1924
1925 fwrite( buffer, sizeof( char ), avail, tst_file );
1926 }
1927
1928 fclose( tst_file );
1929 }
1930
1931 free( dump_name );
1932 }
1933#endif /* DEBUG_HTTP */
1934
1935 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1936 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1937 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001938 else {
1939 xmlChar msg[500];
1940 xmlStrPrintf(msg, 500,
1941 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001942 http_mthd, content_lgth,
1943 "bytes to URI", ctxt->uri,
1944 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001945 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1946 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001947
1948 xmlNanoHTTPClose( http_ctxt );
1949 xmlFree( content_type );
1950 }
1951 }
1952
1953 /* Final cleanups */
1954
1955 xmlFreeHTTPWriteCtxt( ctxt );
1956
1957 return ( close_rc );
1958}
1959
1960/**
1961 * xmlIOHTTPClosePut
1962 *
1963 * @context: The I/O context
1964 *
1965 * Close the transmit HTTP I/O channel and actually send data using a PUT
1966 * HTTP method.
1967 */
1968static int
1969xmlIOHTTPClosePut( void * ctxt ) {
1970 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1971}
1972
1973
1974/**
1975 * xmlIOHTTPClosePost
1976 *
1977 * @context: The I/O context
1978 *
1979 * Close the transmit HTTP I/O channel and actually send data using a POST
1980 * HTTP method.
1981 */
1982static int
1983xmlIOHTTPClosePost( void * ctxt ) {
1984 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1985}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001986#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001987
Owen Taylor3473f882001-02-23 17:55:21 +00001988#endif /* LIBXML_HTTP_ENABLED */
1989
1990#ifdef LIBXML_FTP_ENABLED
1991/************************************************************************
1992 * *
1993 * I/O for FTP file accesses *
1994 * *
1995 ************************************************************************/
1996/**
1997 * xmlIOFTPMatch:
1998 * @filename: the URI for matching
1999 *
2000 * check if the URI matches an FTP one
2001 *
2002 * Returns 1 if matches, 0 otherwise
2003 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002004int
Owen Taylor3473f882001-02-23 17:55:21 +00002005xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002006 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002007 return(1);
2008 return(0);
2009}
2010
2011/**
2012 * xmlIOFTPOpen:
2013 * @filename: the URI for matching
2014 *
2015 * open an FTP I/O channel
2016 *
2017 * Returns an I/O context or NULL in case of error
2018 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002019void *
Owen Taylor3473f882001-02-23 17:55:21 +00002020xmlIOFTPOpen (const char *filename) {
2021 return(xmlNanoFTPOpen(filename));
2022}
2023
2024/**
2025 * xmlIOFTPRead:
2026 * @context: the I/O context
2027 * @buffer: where to drop data
2028 * @len: number of bytes to write
2029 *
2030 * Read @len bytes to @buffer from the I/O channel.
2031 *
2032 * Returns the number of bytes written
2033 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002034int
Owen Taylor3473f882001-02-23 17:55:21 +00002035xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002036 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002037 return(xmlNanoFTPRead(context, &buffer[0], len));
2038}
2039
2040/**
2041 * xmlIOFTPClose:
2042 * @context: the I/O context
2043 *
2044 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002045 *
2046 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002047 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002048int
Owen Taylor3473f882001-02-23 17:55:21 +00002049xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002050 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002051}
2052#endif /* LIBXML_FTP_ENABLED */
2053
2054
2055/**
2056 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002057 * @matchFunc: the xmlInputMatchCallback
2058 * @openFunc: the xmlInputOpenCallback
2059 * @readFunc: the xmlInputReadCallback
2060 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002061 *
2062 * Register a new set of I/O callback for handling parser input.
2063 *
2064 * Returns the registered handler number or -1 in case of error
2065 */
2066int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002067xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2068 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2069 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002070 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2071 return(-1);
2072 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002073 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2074 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2075 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2076 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002077 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002078 return(xmlInputCallbackNr++);
2079}
2080
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002081#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002082/**
2083 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002084 * @matchFunc: the xmlOutputMatchCallback
2085 * @openFunc: the xmlOutputOpenCallback
2086 * @writeFunc: the xmlOutputWriteCallback
2087 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002088 *
2089 * Register a new set of I/O callback for handling output.
2090 *
2091 * Returns the registered handler number or -1 in case of error
2092 */
2093int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002094xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2095 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2096 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002097 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
2098 return(-1);
2099 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002100 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2101 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2102 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2103 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002104 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002105 return(xmlOutputCallbackNr++);
2106}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002107#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002108
2109/**
2110 * xmlRegisterDefaultInputCallbacks:
2111 *
2112 * Registers the default compiled-in I/O handlers.
2113 */
2114void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002115xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002116 if (xmlInputCallbackInitialized)
2117 return;
2118
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002119#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2120 xmlInitPlatformSpecificIo();
2121#endif
2122
Owen Taylor3473f882001-02-23 17:55:21 +00002123 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2124 xmlFileRead, xmlFileClose);
2125#ifdef HAVE_ZLIB_H
2126 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2127 xmlGzfileRead, xmlGzfileClose);
2128#endif /* HAVE_ZLIB_H */
2129
2130#ifdef LIBXML_HTTP_ENABLED
2131 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2132 xmlIOHTTPRead, xmlIOHTTPClose);
2133#endif /* LIBXML_HTTP_ENABLED */
2134
2135#ifdef LIBXML_FTP_ENABLED
2136 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2137 xmlIOFTPRead, xmlIOFTPClose);
2138#endif /* LIBXML_FTP_ENABLED */
2139 xmlInputCallbackInitialized = 1;
2140}
2141
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002142#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002143/**
2144 * xmlRegisterDefaultOutputCallbacks:
2145 *
2146 * Registers the default compiled-in I/O handlers.
2147 */
2148void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002149xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002150 if (xmlOutputCallbackInitialized)
2151 return;
2152
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002153#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2154 xmlInitPlatformSpecificIo();
2155#endif
2156
Owen Taylor3473f882001-02-23 17:55:21 +00002157 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2158 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002159
2160#ifdef LIBXML_HTTP_ENABLED
2161 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2162 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2163#endif
2164
Owen Taylor3473f882001-02-23 17:55:21 +00002165/*********************************
2166 No way a-priori to distinguish between gzipped files from
2167 uncompressed ones except opening if existing then closing
2168 and saving with same compression ratio ... a pain.
2169
2170#ifdef HAVE_ZLIB_H
2171 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2172 xmlGzfileWrite, xmlGzfileClose);
2173#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002174
2175 Nor FTP PUT ....
2176#ifdef LIBXML_FTP_ENABLED
2177 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2178 xmlIOFTPWrite, xmlIOFTPClose);
2179#endif
2180 **********************************/
2181 xmlOutputCallbackInitialized = 1;
2182}
2183
Daniel Veillardf012a642001-07-23 19:10:52 +00002184#ifdef LIBXML_HTTP_ENABLED
2185/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002186 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002187 *
2188 * By default, libxml submits HTTP output requests using the "PUT" method.
2189 * Calling this method changes the HTTP output method to use the "POST"
2190 * method instead.
2191 *
2192 */
2193void
2194xmlRegisterHTTPPostCallbacks( void ) {
2195
2196 /* Register defaults if not done previously */
2197
2198 if ( xmlOutputCallbackInitialized == 0 )
2199 xmlRegisterDefaultOutputCallbacks( );
2200
2201 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2202 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2203 return;
2204}
2205#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002206#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002207
Owen Taylor3473f882001-02-23 17:55:21 +00002208/**
2209 * xmlAllocParserInputBuffer:
2210 * @enc: the charset encoding if known
2211 *
2212 * Create a buffered parser input for progressive parsing
2213 *
2214 * Returns the new parser input or NULL
2215 */
2216xmlParserInputBufferPtr
2217xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2218 xmlParserInputBufferPtr ret;
2219
2220 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2221 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002222 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002223 return(NULL);
2224 }
2225 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002226 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002227 if (ret->buffer == NULL) {
2228 xmlFree(ret);
2229 return(NULL);
2230 }
2231 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2232 ret->encoder = xmlGetCharEncodingHandler(enc);
2233 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002234 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002235 else
2236 ret->raw = NULL;
2237 ret->readcallback = NULL;
2238 ret->closecallback = NULL;
2239 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002240 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002241 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002242
2243 return(ret);
2244}
2245
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002246#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002247/**
2248 * xmlAllocOutputBuffer:
2249 * @encoder: the encoding converter or NULL
2250 *
2251 * Create a buffered parser output
2252 *
2253 * Returns the new parser output or NULL
2254 */
2255xmlOutputBufferPtr
2256xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2257 xmlOutputBufferPtr ret;
2258
2259 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2260 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002261 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002262 return(NULL);
2263 }
2264 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2265 ret->buffer = xmlBufferCreate();
2266 if (ret->buffer == NULL) {
2267 xmlFree(ret);
2268 return(NULL);
2269 }
2270 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2271 ret->encoder = encoder;
2272 if (encoder != NULL) {
2273 ret->conv = xmlBufferCreateSize(4000);
2274 /*
2275 * This call is designed to initiate the encoder state
2276 */
2277 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2278 } else
2279 ret->conv = NULL;
2280 ret->writecallback = NULL;
2281 ret->closecallback = NULL;
2282 ret->context = NULL;
2283 ret->written = 0;
2284
2285 return(ret);
2286}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002287#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002288
2289/**
2290 * xmlFreeParserInputBuffer:
2291 * @in: a buffered parser input
2292 *
2293 * Free up the memory used by a buffered parser input
2294 */
2295void
2296xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002297 if (in == NULL) return;
2298
Owen Taylor3473f882001-02-23 17:55:21 +00002299 if (in->raw) {
2300 xmlBufferFree(in->raw);
2301 in->raw = NULL;
2302 }
2303 if (in->encoder != NULL) {
2304 xmlCharEncCloseFunc(in->encoder);
2305 }
2306 if (in->closecallback != NULL) {
2307 in->closecallback(in->context);
2308 }
2309 if (in->buffer != NULL) {
2310 xmlBufferFree(in->buffer);
2311 in->buffer = NULL;
2312 }
2313
Owen Taylor3473f882001-02-23 17:55:21 +00002314 xmlFree(in);
2315}
2316
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002317#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002318/**
2319 * xmlOutputBufferClose:
2320 * @out: a buffered output
2321 *
2322 * flushes and close the output I/O channel
2323 * and free up all the associated resources
2324 *
2325 * Returns the number of byte written or -1 in case of error.
2326 */
2327int
Daniel Veillard828ce832003-10-08 19:19:10 +00002328xmlOutputBufferClose(xmlOutputBufferPtr out)
2329{
Owen Taylor3473f882001-02-23 17:55:21 +00002330 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002331 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002332
2333 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002334 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002335 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002336 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002337 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002338 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002339 }
2340 written = out->written;
2341 if (out->conv) {
2342 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002343 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002344 }
2345 if (out->encoder != NULL) {
2346 xmlCharEncCloseFunc(out->encoder);
2347 }
2348 if (out->buffer != NULL) {
2349 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002350 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002351 }
2352
Daniel Veillard828ce832003-10-08 19:19:10 +00002353 if (out->error)
2354 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002355 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002356 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002357}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002358#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002359
Daniel Veillard1b243b42004-06-08 10:16:42 +00002360xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002361__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002362 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002363 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002364 void *context = NULL;
2365
2366 if (xmlInputCallbackInitialized == 0)
2367 xmlRegisterDefaultInputCallbacks();
2368
2369 if (URI == NULL) return(NULL);
2370
2371 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002372 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002373 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002374 */
2375 if (context == NULL) {
2376 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2377 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2378 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002379 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002380 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002381 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002382 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002383 }
Owen Taylor3473f882001-02-23 17:55:21 +00002384 }
2385 }
2386 if (context == NULL) {
2387 return(NULL);
2388 }
2389
2390 /*
2391 * Allocate the Input buffer front-end.
2392 */
2393 ret = xmlAllocParserInputBuffer(enc);
2394 if (ret != NULL) {
2395 ret->context = context;
2396 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2397 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002398#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002399 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2400 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002401 if (((z_stream *)context)->avail_in > 4) {
2402 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002403 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002404 if (gzread(context, buff4, 4) == 4) {
2405 if (strncmp(buff4, cptr, 4) == 0)
2406 ret->compressed = 0;
2407 else
2408 ret->compressed = 1;
2409 gzrewind(context);
2410 }
2411 }
2412 }
2413#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002414 }
William M. Brack42331a92004-07-29 07:07:16 +00002415 else
2416 xmlInputCallbackTable[i].closecallback (context);
2417
Owen Taylor3473f882001-02-23 17:55:21 +00002418 return(ret);
2419}
2420
2421/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002422 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002423 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002424 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002425 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002426 * Create a buffered parser input for the progressive parsing of a file
2427 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002428 * Automatic support for ZLIB/Compress compressed document is provided
2429 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002430 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002431 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002432 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002433 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002434xmlParserInputBufferPtr
2435xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2436 if ((xmlParserInputBufferCreateFilenameValue)) {
2437 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2438 }
2439 return __xmlParserInputBufferCreateFilename(URI, enc);
2440}
2441
2442#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002443xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002444__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002445 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002446 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002447 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002448 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002449 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002450 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002451 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002452#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002453 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002454#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002455
Owen Taylor3473f882001-02-23 17:55:21 +00002456 if (xmlOutputCallbackInitialized == 0)
2457 xmlRegisterDefaultOutputCallbacks();
2458
2459 if (URI == NULL) return(NULL);
2460
Daniel Veillard966a31e2004-05-09 02:58:44 +00002461 puri = xmlParseURI(URI);
2462 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002463#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002464 if ((puri->scheme != NULL) &&
2465 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002466 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002467#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002468 /*
2469 * try to limit the damages of the URI unescaping code.
2470 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002471 if ((puri->scheme == NULL) ||
2472 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002473 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2474 xmlFreeURI(puri);
2475 }
Owen Taylor3473f882001-02-23 17:55:21 +00002476
2477 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002478 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002479 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002480 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002481 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002482 if (unescaped != NULL) {
2483#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002484 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002485 context = xmlGzfileOpenW(unescaped, compression);
2486 if (context != NULL) {
2487 ret = xmlAllocOutputBuffer(encoder);
2488 if (ret != NULL) {
2489 ret->context = context;
2490 ret->writecallback = xmlGzfileWrite;
2491 ret->closecallback = xmlGzfileClose;
2492 }
2493 xmlFree(unescaped);
2494 return(ret);
2495 }
2496 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002497#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002498 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2499 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2500 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2501#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2502 /* Need to pass compression parameter into HTTP open calls */
2503 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2504 context = xmlIOHTTPOpenW(unescaped, compression);
2505 else
2506#endif
2507 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2508 if (context != NULL)
2509 break;
2510 }
2511 }
2512 xmlFree(unescaped);
2513 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002514
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002515 /*
2516 * If this failed try with a non-escaped URI this may be a strange
2517 * filename
2518 */
2519 if (context == NULL) {
2520#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002521 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002522 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002523 if (context != NULL) {
2524 ret = xmlAllocOutputBuffer(encoder);
2525 if (ret != NULL) {
2526 ret->context = context;
2527 ret->writecallback = xmlGzfileWrite;
2528 ret->closecallback = xmlGzfileClose;
2529 }
2530 return(ret);
2531 }
2532 }
2533#endif
2534 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2535 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002536 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002537#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2538 /* Need to pass compression parameter into HTTP open calls */
2539 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2540 context = xmlIOHTTPOpenW(URI, compression);
2541 else
2542#endif
2543 context = xmlOutputCallbackTable[i].opencallback(URI);
2544 if (context != NULL)
2545 break;
2546 }
Owen Taylor3473f882001-02-23 17:55:21 +00002547 }
2548 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002549
Owen Taylor3473f882001-02-23 17:55:21 +00002550 if (context == NULL) {
2551 return(NULL);
2552 }
2553
2554 /*
2555 * Allocate the Output buffer front-end.
2556 */
2557 ret = xmlAllocOutputBuffer(encoder);
2558 if (ret != NULL) {
2559 ret->context = context;
2560 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2561 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2562 }
2563 return(ret);
2564}
Daniel Veillard0335a842004-06-02 16:18:40 +00002565
2566/**
2567 * xmlOutputBufferCreateFilename:
2568 * @URI: a C string containing the URI or filename
2569 * @encoder: the encoding converter or NULL
2570 * @compression: the compression ration (0 none, 9 max).
2571 *
2572 * Create a buffered output for the progressive saving of a file
2573 * If filename is "-' then we use stdout as the output.
2574 * Automatic support for ZLIB/Compress compressed document is provided
2575 * by default if found at compile-time.
2576 * TODO: currently if compression is set, the library only support
2577 * writing to a local file.
2578 *
2579 * Returns the new output or NULL
2580 */
2581xmlOutputBufferPtr
2582xmlOutputBufferCreateFilename(const char *URI,
2583 xmlCharEncodingHandlerPtr encoder,
2584 int compression ATTRIBUTE_UNUSED) {
2585 if ((xmlOutputBufferCreateFilenameValue)) {
2586 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2587 }
2588 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2589}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002590#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002591
2592/**
2593 * xmlParserInputBufferCreateFile:
2594 * @file: a FILE*
2595 * @enc: the charset encoding if known
2596 *
2597 * Create a buffered parser input for the progressive parsing of a FILE *
2598 * buffered C I/O
2599 *
2600 * Returns the new parser input or NULL
2601 */
2602xmlParserInputBufferPtr
2603xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2604 xmlParserInputBufferPtr ret;
2605
2606 if (xmlInputCallbackInitialized == 0)
2607 xmlRegisterDefaultInputCallbacks();
2608
2609 if (file == NULL) return(NULL);
2610
2611 ret = xmlAllocParserInputBuffer(enc);
2612 if (ret != NULL) {
2613 ret->context = file;
2614 ret->readcallback = xmlFileRead;
2615 ret->closecallback = xmlFileFlush;
2616 }
2617
2618 return(ret);
2619}
2620
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002621#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002622/**
2623 * xmlOutputBufferCreateFile:
2624 * @file: a FILE*
2625 * @encoder: the encoding converter or NULL
2626 *
2627 * Create a buffered output for the progressive saving to a FILE *
2628 * buffered C I/O
2629 *
2630 * Returns the new parser output or NULL
2631 */
2632xmlOutputBufferPtr
2633xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2634 xmlOutputBufferPtr ret;
2635
2636 if (xmlOutputCallbackInitialized == 0)
2637 xmlRegisterDefaultOutputCallbacks();
2638
2639 if (file == NULL) return(NULL);
2640
2641 ret = xmlAllocOutputBuffer(encoder);
2642 if (ret != NULL) {
2643 ret->context = file;
2644 ret->writecallback = xmlFileWrite;
2645 ret->closecallback = xmlFileFlush;
2646 }
2647
2648 return(ret);
2649}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002650
2651/**
2652 * xmlOutputBufferCreateBuffer:
2653 * @buffer: a xmlBufferPtr
2654 * @encoder: the encoding converter or NULL
2655 *
2656 * Create a buffered output for the progressive saving to a xmlBuffer
2657 *
2658 * Returns the new parser output or NULL
2659 */
2660xmlOutputBufferPtr
2661xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2662 xmlCharEncodingHandlerPtr encoder) {
2663 xmlOutputBufferPtr ret;
2664
2665 if (buffer == NULL) return(NULL);
2666
Rob Richardsa44f2342005-11-09 18:03:45 +00002667 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2668 xmlBufferWrite,
2669 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002670 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002671
2672 return(ret);
2673}
2674
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002675#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002676
2677/**
2678 * xmlParserInputBufferCreateFd:
2679 * @fd: a file descriptor number
2680 * @enc: the charset encoding if known
2681 *
2682 * Create a buffered parser input for the progressive parsing for the input
2683 * from a file descriptor
2684 *
2685 * Returns the new parser input or NULL
2686 */
2687xmlParserInputBufferPtr
2688xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2689 xmlParserInputBufferPtr ret;
2690
2691 if (fd < 0) return(NULL);
2692
2693 ret = xmlAllocParserInputBuffer(enc);
2694 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002695 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002696 ret->readcallback = xmlFdRead;
2697 ret->closecallback = xmlFdClose;
2698 }
2699
2700 return(ret);
2701}
2702
2703/**
2704 * xmlParserInputBufferCreateMem:
2705 * @mem: the memory input
2706 * @size: the length of the memory block
2707 * @enc: the charset encoding if known
2708 *
2709 * Create a buffered parser input for the progressive parsing for the input
2710 * from a memory area.
2711 *
2712 * Returns the new parser input or NULL
2713 */
2714xmlParserInputBufferPtr
2715xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2716 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002717 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002718
2719 if (size <= 0) return(NULL);
2720 if (mem == NULL) return(NULL);
2721
2722 ret = xmlAllocParserInputBuffer(enc);
2723 if (ret != NULL) {
2724 ret->context = (void *) mem;
2725 ret->readcallback = (xmlInputReadCallback) xmlNop;
2726 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002727 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2728 if (errcode != 0) {
2729 xmlFree(ret);
2730 return(NULL);
2731 }
Owen Taylor3473f882001-02-23 17:55:21 +00002732 }
2733
2734 return(ret);
2735}
2736
2737/**
Daniel Veillard53350552003-09-18 13:35:51 +00002738 * xmlParserInputBufferCreateStatic:
2739 * @mem: the memory input
2740 * @size: the length of the memory block
2741 * @enc: the charset encoding if known
2742 *
2743 * Create a buffered parser input for the progressive parsing for the input
2744 * from an immutable memory area. This will not copy the memory area to
2745 * the buffer, but the memory is expected to be available until the end of
2746 * the parsing, this is useful for example when using mmap'ed file.
2747 *
2748 * Returns the new parser input or NULL
2749 */
2750xmlParserInputBufferPtr
2751xmlParserInputBufferCreateStatic(const char *mem, int size,
2752 xmlCharEncoding enc) {
2753 xmlParserInputBufferPtr ret;
2754
2755 if (size <= 0) return(NULL);
2756 if (mem == NULL) return(NULL);
2757
2758 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2759 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002760 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002761 return(NULL);
2762 }
2763 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002764 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002765 if (ret->buffer == NULL) {
2766 xmlFree(ret);
2767 return(NULL);
2768 }
2769 ret->encoder = xmlGetCharEncodingHandler(enc);
2770 if (ret->encoder != NULL)
2771 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2772 else
2773 ret->raw = NULL;
2774 ret->compressed = -1;
2775 ret->context = (void *) mem;
2776 ret->readcallback = NULL;
2777 ret->closecallback = NULL;
2778
2779 return(ret);
2780}
2781
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002782#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002783/**
Owen Taylor3473f882001-02-23 17:55:21 +00002784 * xmlOutputBufferCreateFd:
2785 * @fd: a file descriptor number
2786 * @encoder: the encoding converter or NULL
2787 *
2788 * Create a buffered output for the progressive saving
2789 * to a file descriptor
2790 *
2791 * Returns the new parser output or NULL
2792 */
2793xmlOutputBufferPtr
2794xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2795 xmlOutputBufferPtr ret;
2796
2797 if (fd < 0) return(NULL);
2798
2799 ret = xmlAllocOutputBuffer(encoder);
2800 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002801 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002802 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002803 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002804 }
2805
2806 return(ret);
2807}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002808#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002809
2810/**
2811 * xmlParserInputBufferCreateIO:
2812 * @ioread: an I/O read function
2813 * @ioclose: an I/O close function
2814 * @ioctx: an I/O handler
2815 * @enc: the charset encoding if known
2816 *
2817 * Create a buffered parser input for the progressive parsing for the input
2818 * from an I/O handler
2819 *
2820 * Returns the new parser input or NULL
2821 */
2822xmlParserInputBufferPtr
2823xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2824 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2825 xmlParserInputBufferPtr ret;
2826
2827 if (ioread == NULL) return(NULL);
2828
2829 ret = xmlAllocParserInputBuffer(enc);
2830 if (ret != NULL) {
2831 ret->context = (void *) ioctx;
2832 ret->readcallback = ioread;
2833 ret->closecallback = ioclose;
2834 }
2835
2836 return(ret);
2837}
2838
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002839#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002840/**
2841 * xmlOutputBufferCreateIO:
2842 * @iowrite: an I/O write function
2843 * @ioclose: an I/O close function
2844 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002845 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002846 *
2847 * Create a buffered output for the progressive saving
2848 * to an I/O handler
2849 *
2850 * Returns the new parser output or NULL
2851 */
2852xmlOutputBufferPtr
2853xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2854 xmlOutputCloseCallback ioclose, void *ioctx,
2855 xmlCharEncodingHandlerPtr encoder) {
2856 xmlOutputBufferPtr ret;
2857
2858 if (iowrite == NULL) return(NULL);
2859
2860 ret = xmlAllocOutputBuffer(encoder);
2861 if (ret != NULL) {
2862 ret->context = (void *) ioctx;
2863 ret->writecallback = iowrite;
2864 ret->closecallback = ioclose;
2865 }
2866
2867 return(ret);
2868}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002869#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002870
2871/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002872 * xmlParserInputBufferCreateFilenameDefault:
2873 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2874 *
2875 * Registers a callback for URI input file handling
2876 *
2877 * Returns the old value of the registration function
2878 */
2879xmlParserInputBufferCreateFilenameFunc
2880xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2881{
2882 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2883 if (old == NULL) {
2884 old = __xmlParserInputBufferCreateFilename;
2885 }
2886
2887 xmlParserInputBufferCreateFilenameValue = func;
2888 return(old);
2889}
2890
2891/**
2892 * xmlOutputBufferCreateFilenameDefault:
2893 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2894 *
2895 * Registers a callback for URI output file handling
2896 *
2897 * Returns the old value of the registration function
2898 */
2899xmlOutputBufferCreateFilenameFunc
2900xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2901{
2902 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2903#ifdef LIBXML_OUTPUT_ENABLED
2904 if (old == NULL) {
2905 old = __xmlOutputBufferCreateFilename;
2906 }
2907#endif
2908 xmlOutputBufferCreateFilenameValue = func;
2909 return(old);
2910}
2911
2912/**
Owen Taylor3473f882001-02-23 17:55:21 +00002913 * xmlParserInputBufferPush:
2914 * @in: a buffered parser input
2915 * @len: the size in bytes of the array.
2916 * @buf: an char array
2917 *
2918 * Push the content of the arry in the input buffer
2919 * This routine handle the I18N transcoding to internal UTF-8
2920 * This is used when operating the parser in progressive (push) mode.
2921 *
2922 * Returns the number of chars read and stored in the buffer, or -1
2923 * in case of error.
2924 */
2925int
2926xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2927 int len, const char *buf) {
2928 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002929 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002930
2931 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002932 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002933 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002934 unsigned int use;
2935
Owen Taylor3473f882001-02-23 17:55:21 +00002936 /*
2937 * Store the data in the incoming raw buffer
2938 */
2939 if (in->raw == NULL) {
2940 in->raw = xmlBufferCreate();
2941 }
William M. Bracka3215c72004-07-31 16:24:01 +00002942 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2943 if (ret != 0)
2944 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002945
2946 /*
2947 * convert as much as possible to the parser reading buffer.
2948 */
Daniel Veillard36711902004-02-11 13:25:26 +00002949 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002950 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2951 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002952 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002953 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002954 return(-1);
2955 }
Daniel Veillard36711902004-02-11 13:25:26 +00002956 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002957 } else {
2958 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002959 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2960 if (ret != 0)
2961 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002962 }
2963#ifdef DEBUG_INPUT
2964 xmlGenericError(xmlGenericErrorContext,
2965 "I/O: pushed %d chars, buffer %d/%d\n",
2966 nbchars, in->buffer->use, in->buffer->size);
2967#endif
2968 return(nbchars);
2969}
2970
2971/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002972 * endOfInput:
2973 *
2974 * When reading from an Input channel indicated end of file or error
2975 * don't reread from it again.
2976 */
2977static int
2978endOfInput (void * context ATTRIBUTE_UNUSED,
2979 char * buffer ATTRIBUTE_UNUSED,
2980 int len ATTRIBUTE_UNUSED) {
2981 return(0);
2982}
2983
2984/**
Owen Taylor3473f882001-02-23 17:55:21 +00002985 * xmlParserInputBufferGrow:
2986 * @in: a buffered parser input
2987 * @len: indicative value of the amount of chars to read
2988 *
2989 * Grow up the content of the input buffer, the old data are preserved
2990 * This routine handle the I18N transcoding to internal UTF-8
2991 * This routine is used when operating the parser in normal (pull) mode
2992 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002993 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002994 * onto in->buffer or in->raw
2995 *
2996 * Returns the number of chars read and stored in the buffer, or -1
2997 * in case of error.
2998 */
2999int
3000xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3001 char *buffer = NULL;
3002 int res = 0;
3003 int nbchars = 0;
3004 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00003005 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00003006
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003007 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003008 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003009 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003010
Owen Taylor3473f882001-02-23 17:55:21 +00003011 buffree = in->buffer->size - in->buffer->use;
3012 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003013 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003014 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003015 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003016 }
Owen Taylor3473f882001-02-23 17:55:21 +00003017
Daniel Veillarde5354492002-05-16 08:43:22 +00003018 needSize = in->buffer->use + len + 1;
3019 if (needSize > in->buffer->size){
3020 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003021 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003022 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003023 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003024 }
Owen Taylor3473f882001-02-23 17:55:21 +00003025 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003026 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003027
3028 /*
3029 * Call the read method for this I/O type.
3030 */
3031 if (in->readcallback != NULL) {
3032 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003033 if (res <= 0)
3034 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003035 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003036 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003037 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003038 return(-1);
3039 }
3040 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003041 return(-1);
3042 }
3043 len = res;
3044 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003045 unsigned int use;
3046
Owen Taylor3473f882001-02-23 17:55:21 +00003047 /*
3048 * Store the data in the incoming raw buffer
3049 */
3050 if (in->raw == NULL) {
3051 in->raw = xmlBufferCreate();
3052 }
William M. Bracka3215c72004-07-31 16:24:01 +00003053 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3054 if (res != 0)
3055 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003056
3057 /*
3058 * convert as much as possible to the parser reading buffer.
3059 */
Daniel Veillard36711902004-02-11 13:25:26 +00003060 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003061 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3062 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003063 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003064 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003065 return(-1);
3066 }
Daniel Veillard36711902004-02-11 13:25:26 +00003067 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003068 } else {
3069 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00003070 in->buffer->use += nbchars;
3071 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003072 }
3073#ifdef DEBUG_INPUT
3074 xmlGenericError(xmlGenericErrorContext,
3075 "I/O: read %d chars, buffer %d/%d\n",
3076 nbchars, in->buffer->use, in->buffer->size);
3077#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003078 return(nbchars);
3079}
3080
3081/**
3082 * xmlParserInputBufferRead:
3083 * @in: a buffered parser input
3084 * @len: indicative value of the amount of chars to read
3085 *
3086 * Refresh the content of the input buffer, the old data are considered
3087 * consumed
3088 * This routine handle the I18N transcoding to internal UTF-8
3089 *
3090 * Returns the number of chars read and stored in the buffer, or -1
3091 * in case of error.
3092 */
3093int
3094xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003095 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003096 if (in->readcallback != NULL)
3097 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003098 else if ((in->buffer != NULL) &&
3099 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3100 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003101 else
3102 return(-1);
3103}
3104
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003105#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003106/**
3107 * xmlOutputBufferWrite:
3108 * @out: a buffered parser output
3109 * @len: the size in bytes of the array.
3110 * @buf: an char array
3111 *
3112 * Write the content of the array in the output I/O buffer
3113 * This routine handle the I18N transcoding from internal UTF-8
3114 * The buffer is lossless, i.e. will store in case of partial
3115 * or delayed writes.
3116 *
3117 * Returns the number of chars immediately written, or -1
3118 * in case of error.
3119 */
3120int
3121xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3122 int nbchars = 0; /* number of chars to output to I/O */
3123 int ret; /* return from function call */
3124 int written = 0; /* number of char written to I/O so far */
3125 int chunk; /* number of byte curreent processed from buf */
3126
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003127 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003128 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003129 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003130
3131 do {
3132 chunk = len;
3133 if (chunk > 4 * MINLEN)
3134 chunk = 4 * MINLEN;
3135
3136 /*
3137 * first handle encoding stuff.
3138 */
3139 if (out->encoder != NULL) {
3140 /*
3141 * Store the data in the incoming raw buffer
3142 */
3143 if (out->conv == NULL) {
3144 out->conv = xmlBufferCreate();
3145 }
William M. Bracka3215c72004-07-31 16:24:01 +00003146 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3147 if (ret != 0)
3148 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003149
3150 if ((out->buffer->use < MINLEN) && (chunk == len))
3151 goto done;
3152
3153 /*
3154 * convert as much as possible to the parser reading buffer.
3155 */
3156 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003157 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003158 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003159 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003160 return(-1);
3161 }
3162 nbchars = out->conv->use;
3163 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003164 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3165 if (ret != 0)
3166 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003167 nbchars = out->buffer->use;
3168 }
3169 buf += chunk;
3170 len -= chunk;
3171
3172 if ((nbchars < MINLEN) && (len <= 0))
3173 goto done;
3174
3175 if (out->writecallback) {
3176 /*
3177 * second write the stuff to the I/O channel
3178 */
3179 if (out->encoder != NULL) {
3180 ret = out->writecallback(out->context,
3181 (const char *)out->conv->content, nbchars);
3182 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003183 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003184 } else {
3185 ret = out->writecallback(out->context,
3186 (const char *)out->buffer->content, nbchars);
3187 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003188 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003189 }
3190 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003191 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003192 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003193 return(ret);
3194 }
3195 out->written += ret;
3196 }
3197 written += nbchars;
3198 } while (len > 0);
3199
3200done:
3201#ifdef DEBUG_INPUT
3202 xmlGenericError(xmlGenericErrorContext,
3203 "I/O: wrote %d chars\n", written);
3204#endif
3205 return(written);
3206}
3207
3208/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003209 * xmlEscapeContent:
3210 * @out: a pointer to an array of bytes to store the result
3211 * @outlen: the length of @out
3212 * @in: a pointer to an array of unescaped UTF-8 bytes
3213 * @inlen: the length of @in
3214 *
3215 * Take a block of UTF-8 chars in and escape them.
3216 * Returns 0 if success, or -1 otherwise
3217 * The value of @inlen after return is the number of octets consumed
3218 * if the return value is positive, else unpredictable.
3219 * The value of @outlen after return is the number of octets consumed.
3220 */
3221static int
3222xmlEscapeContent(unsigned char* out, int *outlen,
3223 const xmlChar* in, int *inlen) {
3224 unsigned char* outstart = out;
3225 const unsigned char* base = in;
3226 unsigned char* outend = out + *outlen;
3227 const unsigned char* inend;
3228
3229 inend = in + (*inlen);
3230
3231 while ((in < inend) && (out < outend)) {
3232 if (*in == '<') {
3233 if (outend - out < 4) break;
3234 *out++ = '&';
3235 *out++ = 'l';
3236 *out++ = 't';
3237 *out++ = ';';
3238 } else if (*in == '>') {
3239 if (outend - out < 4) break;
3240 *out++ = '&';
3241 *out++ = 'g';
3242 *out++ = 't';
3243 *out++ = ';';
3244 } else if (*in == '&') {
3245 if (outend - out < 5) break;
3246 *out++ = '&';
3247 *out++ = 'a';
3248 *out++ = 'm';
3249 *out++ = 'p';
3250 *out++ = ';';
3251 } else if (*in == '\r') {
3252 if (outend - out < 5) break;
3253 *out++ = '&';
3254 *out++ = '#';
3255 *out++ = '1';
3256 *out++ = '3';
3257 *out++ = ';';
3258 } else {
3259 *out++ = (unsigned char) *in;
3260 }
3261 ++in;
3262 }
3263 *outlen = out - outstart;
3264 *inlen = in - base;
3265 return(0);
3266}
3267
3268/**
3269 * xmlOutputBufferWriteEscape:
3270 * @out: a buffered parser output
3271 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003272 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003273 *
3274 * Write the content of the string in the output I/O buffer
3275 * This routine escapes the caracters and then handle the I18N
3276 * transcoding from internal UTF-8
3277 * The buffer is lossless, i.e. will store in case of partial
3278 * or delayed writes.
3279 *
3280 * Returns the number of chars immediately written, or -1
3281 * in case of error.
3282 */
3283int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003284xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3285 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003286 int nbchars = 0; /* number of chars to output to I/O */
3287 int ret; /* return from function call */
3288 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003289 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003290 int chunk; /* number of byte currently processed from str */
3291 int len; /* number of bytes in str */
3292 int cons; /* byte from str consumed */
3293
Daniel Veillardce244ad2004-11-05 10:03:46 +00003294 if ((out == NULL) || (out->error) || (str == NULL) ||
3295 (out->buffer == NULL) ||
3296 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003297 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003298 if (len < 0) return(0);
3299 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003300 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003301
3302 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003303 oldwritten = written;
3304
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003305 /*
3306 * how many bytes to consume and how many bytes to store.
3307 */
3308 cons = len;
3309 chunk = (out->buffer->size - out->buffer->use) - 1;
3310
3311 /*
3312 * first handle encoding stuff.
3313 */
3314 if (out->encoder != NULL) {
3315 /*
3316 * Store the data in the incoming raw buffer
3317 */
3318 if (out->conv == NULL) {
3319 out->conv = xmlBufferCreate();
3320 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003321 ret = escaping(out->buffer->content + out->buffer->use ,
3322 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003323 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003324 return(-1);
3325 out->buffer->use += chunk;
3326 out->buffer->content[out->buffer->use] = 0;
3327
3328 if ((out->buffer->use < MINLEN) && (cons == len))
3329 goto done;
3330
3331 /*
3332 * convert as much as possible to the output buffer.
3333 */
3334 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3335 if ((ret < 0) && (ret != -3)) {
3336 xmlIOErr(XML_IO_ENCODER, NULL);
3337 out->error = XML_IO_ENCODER;
3338 return(-1);
3339 }
3340 nbchars = out->conv->use;
3341 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003342 ret = escaping(out->buffer->content + out->buffer->use ,
3343 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003344 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003345 return(-1);
3346 out->buffer->use += chunk;
3347 out->buffer->content[out->buffer->use] = 0;
3348 nbchars = out->buffer->use;
3349 }
3350 str += cons;
3351 len -= cons;
3352
3353 if ((nbchars < MINLEN) && (len <= 0))
3354 goto done;
3355
3356 if (out->writecallback) {
3357 /*
3358 * second write the stuff to the I/O channel
3359 */
3360 if (out->encoder != NULL) {
3361 ret = out->writecallback(out->context,
3362 (const char *)out->conv->content, nbchars);
3363 if (ret >= 0)
3364 xmlBufferShrink(out->conv, ret);
3365 } else {
3366 ret = out->writecallback(out->context,
3367 (const char *)out->buffer->content, nbchars);
3368 if (ret >= 0)
3369 xmlBufferShrink(out->buffer, ret);
3370 }
3371 if (ret < 0) {
3372 xmlIOErr(XML_IO_WRITE, NULL);
3373 out->error = XML_IO_WRITE;
3374 return(ret);
3375 }
3376 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003377 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3378 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003379 }
3380 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003381 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003382
3383done:
3384#ifdef DEBUG_INPUT
3385 xmlGenericError(xmlGenericErrorContext,
3386 "I/O: wrote %d chars\n", written);
3387#endif
3388 return(written);
3389}
3390
3391/**
Owen Taylor3473f882001-02-23 17:55:21 +00003392 * xmlOutputBufferWriteString:
3393 * @out: a buffered parser output
3394 * @str: a zero terminated C string
3395 *
3396 * Write the content of the string in the output I/O buffer
3397 * This routine handle the I18N transcoding from internal UTF-8
3398 * The buffer is lossless, i.e. will store in case of partial
3399 * or delayed writes.
3400 *
3401 * Returns the number of chars immediately written, or -1
3402 * in case of error.
3403 */
3404int
3405xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3406 int len;
3407
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003408 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003409 if (str == NULL)
3410 return(-1);
3411 len = strlen(str);
3412
3413 if (len > 0)
3414 return(xmlOutputBufferWrite(out, len, str));
3415 return(len);
3416}
3417
3418/**
3419 * xmlOutputBufferFlush:
3420 * @out: a buffered output
3421 *
3422 * flushes the output I/O channel
3423 *
3424 * Returns the number of byte written or -1 in case of error.
3425 */
3426int
3427xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3428 int nbchars = 0, ret = 0;
3429
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003430 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003431 /*
3432 * first handle encoding stuff.
3433 */
3434 if ((out->conv != NULL) && (out->encoder != NULL)) {
3435 /*
3436 * convert as much as possible to the parser reading buffer.
3437 */
3438 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3439 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003440 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003441 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003442 return(-1);
3443 }
3444 }
3445
3446 /*
3447 * second flush the stuff to the I/O channel
3448 */
3449 if ((out->conv != NULL) && (out->encoder != NULL) &&
3450 (out->writecallback != NULL)) {
3451 ret = out->writecallback(out->context,
3452 (const char *)out->conv->content, out->conv->use);
3453 if (ret >= 0)
3454 xmlBufferShrink(out->conv, ret);
3455 } else if (out->writecallback != NULL) {
3456 ret = out->writecallback(out->context,
3457 (const char *)out->buffer->content, out->buffer->use);
3458 if (ret >= 0)
3459 xmlBufferShrink(out->buffer, ret);
3460 }
3461 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003462 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003463 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003464 return(ret);
3465 }
3466 out->written += ret;
3467
3468#ifdef DEBUG_INPUT
3469 xmlGenericError(xmlGenericErrorContext,
3470 "I/O: flushed %d chars\n", ret);
3471#endif
3472 return(ret);
3473}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003474#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003475
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003476/**
Owen Taylor3473f882001-02-23 17:55:21 +00003477 * xmlParserGetDirectory:
3478 * @filename: the path to a file
3479 *
3480 * lookup the directory for that file
3481 *
3482 * Returns a new allocated string containing the directory, or NULL.
3483 */
3484char *
3485xmlParserGetDirectory(const char *filename) {
3486 char *ret = NULL;
3487 char dir[1024];
3488 char *cur;
3489 char sep = '/';
3490
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003491#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3492 return NULL;
3493#endif
3494
Owen Taylor3473f882001-02-23 17:55:21 +00003495 if (xmlInputCallbackInitialized == 0)
3496 xmlRegisterDefaultInputCallbacks();
3497
3498 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003499#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003500 sep = '\\';
3501#endif
3502
3503 strncpy(dir, filename, 1023);
3504 dir[1023] = 0;
3505 cur = &dir[strlen(dir)];
3506 while (cur > dir) {
3507 if (*cur == sep) break;
3508 cur --;
3509 }
3510 if (*cur == sep) {
3511 if (cur == dir) dir[1] = 0;
3512 else *cur = 0;
3513 ret = xmlMemStrdup(dir);
3514 } else {
3515 if (getcwd(dir, 1024) != NULL) {
3516 dir[1023] = 0;
3517 ret = xmlMemStrdup(dir);
3518 }
3519 }
3520 return(ret);
3521}
3522
3523/****************************************************************
3524 * *
3525 * External entities loading *
3526 * *
3527 ****************************************************************/
3528
Daniel Veillarda840b692003-10-19 13:35:37 +00003529/**
3530 * xmlCheckHTTPInput:
3531 * @ctxt: an XML parser context
3532 * @ret: an XML parser input
3533 *
3534 * Check an input in case it was created from an HTTP stream, in that
3535 * case it will handle encoding and update of the base URL in case of
3536 * redirection. It also checks for HTTP errors in which case the input
3537 * is cleanly freed up and an appropriate error is raised in context
3538 *
3539 * Returns the input or NULL in case of HTTP error.
3540 */
3541xmlParserInputPtr
3542xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3543#ifdef LIBXML_HTTP_ENABLED
3544 if ((ret != NULL) && (ret->buf != NULL) &&
3545 (ret->buf->readcallback == xmlIOHTTPRead) &&
3546 (ret->buf->context != NULL)) {
3547 const char *encoding;
3548 const char *redir;
3549 const char *mime;
3550 int code;
3551
3552 code = xmlNanoHTTPReturnCode(ret->buf->context);
3553 if (code >= 400) {
3554 /* fatal error */
3555 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003556 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003557 (const char *) ret->filename);
3558 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003559 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003560 xmlFreeInputStream(ret);
3561 ret = NULL;
3562 } else {
3563
3564 mime = xmlNanoHTTPMimeType(ret->buf->context);
3565 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3566 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3567 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3568 if (encoding != NULL) {
3569 xmlCharEncodingHandlerPtr handler;
3570
3571 handler = xmlFindCharEncodingHandler(encoding);
3572 if (handler != NULL) {
3573 xmlSwitchInputEncoding(ctxt, ret, handler);
3574 } else {
3575 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3576 "Unknown encoding %s",
3577 BAD_CAST encoding, NULL);
3578 }
3579 if (ret->encoding == NULL)
3580 ret->encoding = xmlStrdup(BAD_CAST encoding);
3581 }
3582#if 0
3583 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3584#endif
3585 }
3586 redir = xmlNanoHTTPRedir(ret->buf->context);
3587 if (redir != NULL) {
3588 if (ret->filename != NULL)
3589 xmlFree((xmlChar *) ret->filename);
3590 if (ret->directory != NULL) {
3591 xmlFree((xmlChar *) ret->directory);
3592 ret->directory = NULL;
3593 }
3594 ret->filename =
3595 (char *) xmlStrdup((const xmlChar *) redir);
3596 }
3597 }
3598 }
3599#endif
3600 return(ret);
3601}
3602
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003603static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003604 const char *path;
3605
3606 if (URL == NULL)
3607 return(0);
3608
Daniel Veillardf4862f02002-09-10 11:13:43 +00003609 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003610#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003611 path = &URL[17];
3612#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003613 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003614#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003615 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003616#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003617 path = &URL[8];
3618#else
3619 path = &URL[7];
3620#endif
3621 } else
3622 path = URL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003623
3624 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003625}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003626
Daniel Veillardad4e2962006-09-21 08:36:38 +00003627#ifdef LIBXML_CATALOG_ENABLED
3628
3629/**
3630 * xmlResolveResourceFromCatalog:
3631 * @URL: the URL for the entity to load
3632 * @ID: the System ID for the entity to load
3633 * @ctxt: the context in which the entity is called or NULL
3634 *
3635 * Resolves the URL and ID against the appropriate catalog.
3636 * This function is used by xmlDefaultExternalEntityLoader and
3637 * xmlNoNetExternalEntityLoader.
3638 *
3639 * Returns a new allocated URL, or NULL.
3640 */
William M. Brack38d452a2007-05-22 16:00:06 +00003641static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003642xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3643 xmlParserCtxtPtr ctxt) {
3644 xmlChar *resource = NULL;
3645 xmlCatalogAllow pref;
3646
3647 /*
3648 * If the resource doesn't exists as a file,
3649 * try to load it from the resource pointed in the catalogs
3650 */
3651 pref = xmlCatalogGetDefaults();
3652
3653 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3654 /*
3655 * Do a local lookup
3656 */
3657 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3658 ((pref == XML_CATA_ALLOW_ALL) ||
3659 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3660 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3661 (const xmlChar *)ID,
3662 (const xmlChar *)URL);
3663 }
3664 /*
3665 * Try a global lookup
3666 */
3667 if ((resource == NULL) &&
3668 ((pref == XML_CATA_ALLOW_ALL) ||
3669 (pref == XML_CATA_ALLOW_GLOBAL))) {
3670 resource = xmlCatalogResolve((const xmlChar *)ID,
3671 (const xmlChar *)URL);
3672 }
3673 if ((resource == NULL) && (URL != NULL))
3674 resource = xmlStrdup((const xmlChar *) URL);
3675
3676 /*
3677 * TODO: do an URI lookup on the reference
3678 */
3679 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3680 xmlChar *tmp = NULL;
3681
3682 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3683 ((pref == XML_CATA_ALLOW_ALL) ||
3684 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3685 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3686 }
3687 if ((tmp == NULL) &&
3688 ((pref == XML_CATA_ALLOW_ALL) ||
3689 (pref == XML_CATA_ALLOW_GLOBAL))) {
3690 tmp = xmlCatalogResolveURI(resource);
3691 }
3692
3693 if (tmp != NULL) {
3694 xmlFree(resource);
3695 resource = tmp;
3696 }
3697 }
3698 }
3699
3700 return resource;
3701}
3702
3703#endif
3704
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003705/**
Owen Taylor3473f882001-02-23 17:55:21 +00003706 * xmlDefaultExternalEntityLoader:
3707 * @URL: the URL for the entity to load
3708 * @ID: the System ID for the entity to load
3709 * @ctxt: the context in which the entity is called or NULL
3710 *
3711 * By default we don't load external entitites, yet.
3712 *
3713 * Returns a new allocated xmlParserInputPtr, or NULL.
3714 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003715static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003716xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003717 xmlParserCtxtPtr ctxt)
3718{
Owen Taylor3473f882001-02-23 17:55:21 +00003719 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003720 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003721
Owen Taylor3473f882001-02-23 17:55:21 +00003722#ifdef DEBUG_EXTERNAL_ENTITIES
3723 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003724 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003725#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00003726 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3727 int options = ctxt->options;
3728
3729 ctxt->options -= XML_PARSE_NONET;
3730 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3731 ctxt->options = options;
3732 return(ret);
3733 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003734#ifdef LIBXML_CATALOG_ENABLED
3735 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003736#endif
3737
3738 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003739 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003740
3741 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003742 if (ID == NULL)
3743 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003744 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003745 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003746 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003747 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003748 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003749 xmlFree(resource);
3750 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003751}
3752
3753static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3754 xmlDefaultExternalEntityLoader;
3755
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003756/**
Owen Taylor3473f882001-02-23 17:55:21 +00003757 * xmlSetExternalEntityLoader:
3758 * @f: the new entity resolver function
3759 *
3760 * Changes the defaultexternal entity resolver function for the application
3761 */
3762void
3763xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3764 xmlCurrentExternalEntityLoader = f;
3765}
3766
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003767/**
Owen Taylor3473f882001-02-23 17:55:21 +00003768 * xmlGetExternalEntityLoader:
3769 *
3770 * Get the default external entity resolver function for the application
3771 *
3772 * Returns the xmlExternalEntityLoader function pointer
3773 */
3774xmlExternalEntityLoader
3775xmlGetExternalEntityLoader(void) {
3776 return(xmlCurrentExternalEntityLoader);
3777}
3778
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003779/**
Owen Taylor3473f882001-02-23 17:55:21 +00003780 * xmlLoadExternalEntity:
3781 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003782 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003783 * @ctxt: the context in which the entity is called or NULL
3784 *
3785 * Load an external entity, note that the use of this function for
3786 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003787 *
3788 * Returns the xmlParserInputPtr or NULL
3789 */
3790xmlParserInputPtr
3791xmlLoadExternalEntity(const char *URL, const char *ID,
3792 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003793 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003794 char *canonicFilename;
3795 xmlParserInputPtr ret;
3796
3797 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3798 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003799 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003800 return(NULL);
3801 }
3802
3803 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3804 xmlFree(canonicFilename);
3805 return(ret);
3806 }
Owen Taylor3473f882001-02-23 17:55:21 +00003807 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3808}
3809
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003810/************************************************************************
3811 * *
3812 * Disabling Network access *
3813 * *
3814 ************************************************************************/
3815
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003816/**
3817 * xmlNoNetExternalEntityLoader:
3818 * @URL: the URL for the entity to load
3819 * @ID: the System ID for the entity to load
3820 * @ctxt: the context in which the entity is called or NULL
3821 *
3822 * A specific entity loader disabling network accesses, though still
3823 * allowing local catalog accesses for resolution.
3824 *
3825 * Returns a new allocated xmlParserInputPtr, or NULL.
3826 */
3827xmlParserInputPtr
3828xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3829 xmlParserCtxtPtr ctxt) {
3830 xmlParserInputPtr input = NULL;
3831 xmlChar *resource = NULL;
3832
3833#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00003834 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003835#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00003836
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003837 if (resource == NULL)
3838 resource = (xmlChar *) URL;
3839
3840 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003841 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3842 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003843 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003844 if (resource != (xmlChar *) URL)
3845 xmlFree(resource);
3846 return(NULL);
3847 }
3848 }
3849 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3850 if (resource != (xmlChar *) URL)
3851 xmlFree(resource);
3852 return(input);
3853}
3854
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003855#define bottom_xmlIO
3856#include "elfgcchack.h"