blob: 34448e0b422591fd39b9a96b6a65138df5c997f4 [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 Veillard5cdbbd22007-06-12 09:39:14 +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
Daniel Veillard5cdbbd22007-06-12 09:39:14 +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
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000859 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
860 /* lots of generators seems to lazy to read RFC 1738 */
861#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
862 path = &filename[6];
863#else
864 path = &filename[5];
865#endif
Daniel Veillardfe703322001-08-14 12:18:09 +0000866 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000867 path = filename;
868
869 if (path == NULL)
870 return(NULL);
871 if (!xmlCheckFilename(path))
872 return(NULL);
873
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000874#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
875 fd = xmlWrapOpen(path, 0);
876#else
877 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000878#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000879 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000880 return((void *) fd);
881}
882
883/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000884 * xmlFileOpen:
885 * @filename: the URI for matching
886 *
887 * Wrapper around xmlFileOpen_real that try it with an unescaped
888 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000889 *
890 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000891 */
892void *
893xmlFileOpen (const char *filename) {
894 char *unescaped;
895 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000896
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000897 retval = xmlFileOpen_real(filename);
898 if (retval == NULL) {
899 unescaped = xmlURIUnescapeString(filename, 0, NULL);
900 if (unescaped != NULL) {
901 retval = xmlFileOpen_real(unescaped);
902 xmlFree(unescaped);
903 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000904 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000905
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000906 return retval;
907}
908
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000909#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000910/**
Owen Taylor3473f882001-02-23 17:55:21 +0000911 * xmlFileOpenW:
912 * @filename: the URI for matching
913 *
914 * output to from FILE *,
915 * if @filename is "-" then the standard output is used
916 *
917 * Returns an I/O context or NULL in case of error
918 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000919static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000920xmlFileOpenW (const char *filename) {
921 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000922 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000923
924 if (!strcmp(filename, "-")) {
925 fd = stdout;
926 return((void *) fd);
927 }
928
Daniel Veillardf4862f02002-09-10 11:13:43 +0000929 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000930#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000931 path = &filename[17];
932#else
Owen Taylor3473f882001-02-23 17:55:21 +0000933 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000934#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000935 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000936#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000937 path = &filename[8];
938#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000939 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000940#endif
941 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000942 path = filename;
943
944 if (path == NULL)
945 return(NULL);
946
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000947#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
948 fd = xmlWrapOpen(path, 1);
949#else
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000950 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000951#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000952
Daniel Veillardf7416012006-04-27 08:15:20 +0000953 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000954 return((void *) fd);
955}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000956#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000957
958/**
959 * xmlFileRead:
960 * @context: the I/O context
961 * @buffer: where to drop data
962 * @len: number of bytes to write
963 *
964 * Read @len bytes to @buffer from the I/O channel.
965 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000966 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000967 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000968int
Owen Taylor3473f882001-02-23 17:55:21 +0000969xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000970 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000971 if ((context == NULL) || (buffer == NULL))
972 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000973 ret = fread(&buffer[0], 1, len, (FILE *) context);
974 if (ret < 0) xmlIOErr(0, "fread()");
975 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000976}
977
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000978#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000979/**
980 * xmlFileWrite:
981 * @context: the I/O context
982 * @buffer: where to drop data
983 * @len: number of bytes to write
984 *
985 * Write @len bytes from @buffer to the I/O channel.
986 *
987 * Returns the number of bytes written
988 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000989static int
Owen Taylor3473f882001-02-23 17:55:21 +0000990xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000991 int items;
992
Daniel Veillardce682bc2004-11-05 17:22:25 +0000993 if ((context == NULL) || (buffer == NULL))
994 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000995 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000996 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000997 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000998 return(-1);
999 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001000 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001001}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001002#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001003
1004/**
1005 * xmlFileClose:
1006 * @context: the I/O context
1007 *
1008 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001009 *
1010 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001011 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001012int
Owen Taylor3473f882001-02-23 17:55:21 +00001013xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001014 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001015 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001016
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001017 if (context == NULL)
1018 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001019 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001020 if ((fil == stdout) || (fil == stderr)) {
1021 ret = fflush(fil);
1022 if (ret < 0)
1023 xmlIOErr(0, "fflush()");
1024 return(0);
1025 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001026 if (fil == stdin)
1027 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001028 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1029 if (ret < 0)
1030 xmlIOErr(0, "fclose()");
1031 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001032}
1033
1034/**
1035 * xmlFileFlush:
1036 * @context: the I/O context
1037 *
1038 * Flush an I/O channel
1039 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001040static int
Owen Taylor3473f882001-02-23 17:55:21 +00001041xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001042 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001043
1044 if (context == NULL)
1045 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001046 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1047 if (ret < 0)
1048 xmlIOErr(0, "fflush()");
1049 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001050}
1051
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001052#ifdef LIBXML_OUTPUT_ENABLED
1053/**
1054 * xmlBufferWrite:
1055 * @context: the xmlBuffer
1056 * @buffer: the data to write
1057 * @len: number of bytes to write
1058 *
1059 * Write @len bytes from @buffer to the xml buffer
1060 *
1061 * Returns the number of bytes written
1062 */
1063static int
1064xmlBufferWrite (void * context, const char * buffer, int len) {
1065 int ret;
1066
1067 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1068 if (ret != 0)
1069 return(-1);
1070 return(len);
1071}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001072#endif
1073
Owen Taylor3473f882001-02-23 17:55:21 +00001074#ifdef HAVE_ZLIB_H
1075/************************************************************************
1076 * *
1077 * I/O for compressed file accesses *
1078 * *
1079 ************************************************************************/
1080/**
1081 * xmlGzfileMatch:
1082 * @filename: the URI for matching
1083 *
1084 * input from compressed file test
1085 *
1086 * Returns 1 if matches, 0 otherwise
1087 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001088static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001089xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001090 return(1);
1091}
1092
1093/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001094 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001095 * @filename: the URI for matching
1096 *
1097 * input from compressed file open
1098 * if @filename is " " then the standard input is used
1099 *
1100 * Returns an I/O context or NULL in case of error
1101 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001102static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001103xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001104 const char *path = NULL;
1105 gzFile fd;
1106
1107 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001108 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001109 return((void *) fd);
1110 }
1111
Daniel Veillardf4862f02002-09-10 11:13:43 +00001112 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001113#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001114 path = &filename[17];
1115#else
Owen Taylor3473f882001-02-23 17:55:21 +00001116 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001117#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001118 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001119#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001120 path = &filename[8];
1121#else
Owen Taylor3473f882001-02-23 17:55:21 +00001122 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001123#endif
1124 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001125 path = filename;
1126
1127 if (path == NULL)
1128 return(NULL);
1129 if (!xmlCheckFilename(path))
1130 return(NULL);
1131
1132 fd = gzopen(path, "rb");
1133 return((void *) fd);
1134}
1135
1136/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001137 * xmlGzfileOpen:
1138 * @filename: the URI for matching
1139 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001140 * Wrapper around xmlGzfileOpen if the open fais, it will
1141 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001142 */
1143static void *
1144xmlGzfileOpen (const char *filename) {
1145 char *unescaped;
1146 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001147
1148 retval = xmlGzfileOpen_real(filename);
1149 if (retval == NULL) {
1150 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1151 if (unescaped != NULL) {
1152 retval = xmlGzfileOpen_real(unescaped);
1153 }
1154 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001155 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001156 return retval;
1157}
1158
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001159#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001160/**
Owen Taylor3473f882001-02-23 17:55:21 +00001161 * xmlGzfileOpenW:
1162 * @filename: the URI for matching
1163 * @compression: the compression factor (0 - 9 included)
1164 *
1165 * input from compressed file open
1166 * if @filename is " " then the standard input is used
1167 *
1168 * Returns an I/O context or NULL in case of error
1169 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001170static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001171xmlGzfileOpenW (const char *filename, int compression) {
1172 const char *path = NULL;
1173 char mode[15];
1174 gzFile fd;
1175
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001176 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001177 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001178 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001179 return((void *) fd);
1180 }
1181
Daniel Veillardf4862f02002-09-10 11:13:43 +00001182 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001183#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001184 path = &filename[17];
1185#else
Owen Taylor3473f882001-02-23 17:55:21 +00001186 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001187#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001188 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001189#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001190 path = &filename[8];
1191#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001192 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001193#endif
1194 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001195 path = filename;
1196
1197 if (path == NULL)
1198 return(NULL);
1199
1200 fd = gzopen(path, mode);
1201 return((void *) fd);
1202}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001203#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001204
1205/**
1206 * xmlGzfileRead:
1207 * @context: the I/O context
1208 * @buffer: where to drop data
1209 * @len: number of bytes to write
1210 *
1211 * Read @len bytes to @buffer from the compressed I/O channel.
1212 *
1213 * Returns the number of bytes written
1214 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001215static int
Owen Taylor3473f882001-02-23 17:55:21 +00001216xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001217 int ret;
1218
1219 ret = gzread((gzFile) context, &buffer[0], len);
1220 if (ret < 0) xmlIOErr(0, "gzread()");
1221 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001222}
1223
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001224#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001225/**
1226 * xmlGzfileWrite:
1227 * @context: the I/O context
1228 * @buffer: where to drop data
1229 * @len: number of bytes to write
1230 *
1231 * Write @len bytes from @buffer to the compressed I/O channel.
1232 *
1233 * Returns the number of bytes written
1234 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001235static int
Owen Taylor3473f882001-02-23 17:55:21 +00001236xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001237 int ret;
1238
1239 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1240 if (ret < 0) xmlIOErr(0, "gzwrite()");
1241 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001242}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001243#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001244
1245/**
1246 * xmlGzfileClose:
1247 * @context: the I/O context
1248 *
1249 * Close a compressed I/O channel
1250 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001251static int
Owen Taylor3473f882001-02-23 17:55:21 +00001252xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001253 int ret;
1254
1255 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1256 if (ret < 0) xmlIOErr(0, "gzclose()");
1257 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001258}
1259#endif /* HAVE_ZLIB_H */
1260
1261#ifdef LIBXML_HTTP_ENABLED
1262/************************************************************************
1263 * *
1264 * I/O for HTTP file accesses *
1265 * *
1266 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001267
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001268#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001269typedef struct xmlIOHTTPWriteCtxt_
1270{
1271 int compression;
1272
1273 char * uri;
1274
1275 void * doc_buff;
1276
1277} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1278
1279#ifdef HAVE_ZLIB_H
1280
1281#define DFLT_WBITS ( -15 )
1282#define DFLT_MEM_LVL ( 8 )
1283#define GZ_MAGIC1 ( 0x1f )
1284#define GZ_MAGIC2 ( 0x8b )
1285#define LXML_ZLIB_OS_CODE ( 0x03 )
1286#define INIT_HTTP_BUFF_SIZE ( 32768 )
1287#define DFLT_ZLIB_RATIO ( 5 )
1288
1289/*
1290** Data structure and functions to work with sending compressed data
1291** via HTTP.
1292*/
1293
1294typedef struct xmlZMemBuff_
1295{
1296 unsigned long size;
1297 unsigned long crc;
1298
1299 unsigned char * zbuff;
1300 z_stream zctrl;
1301
1302} xmlZMemBuff, *xmlZMemBuffPtr;
1303
1304/**
1305 * append_reverse_ulong
1306 * @buff: Compressed memory buffer
1307 * @data: Unsigned long to append
1308 *
1309 * Append a unsigned long in reverse byte order to the end of the
1310 * memory buffer.
1311 */
1312static void
1313append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1314
1315 int idx;
1316
1317 if ( buff == NULL )
1318 return;
1319
1320 /*
1321 ** This is plagiarized from putLong in gzio.c (zlib source) where
1322 ** the number "4" is hardcoded. If zlib is ever patched to
1323 ** support 64 bit file sizes, this code would need to be patched
1324 ** as well.
1325 */
1326
1327 for ( idx = 0; idx < 4; idx++ ) {
1328 *buff->zctrl.next_out = ( data & 0xff );
1329 data >>= 8;
1330 buff->zctrl.next_out++;
1331 }
1332
1333 return;
1334}
1335
1336/**
1337 *
1338 * xmlFreeZMemBuff
1339 * @buff: The memory buffer context to clear
1340 *
1341 * Release all the resources associated with the compressed memory buffer.
1342 */
1343static void
1344xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001345
1346#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001347 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001348#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001349
1350 if ( buff == NULL )
1351 return;
1352
1353 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001354#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001355 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001356 if ( z_err != Z_OK )
1357 xmlGenericError( xmlGenericErrorContext,
1358 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1359 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001360#else
1361 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001362#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001363
1364 xmlFree( buff );
1365 return;
1366}
1367
1368/**
1369 * xmlCreateZMemBuff
1370 *@compression: Compression value to use
1371 *
1372 * Create a memory buffer to hold the compressed XML document. The
1373 * compressed document in memory will end up being identical to what
1374 * would be created if gzopen/gzwrite/gzclose were being used to
1375 * write the document to disk. The code for the header/trailer data to
1376 * the compression is plagiarized from the zlib source files.
1377 */
1378static void *
1379xmlCreateZMemBuff( int compression ) {
1380
1381 int z_err;
1382 int hdr_lgth;
1383 xmlZMemBuffPtr buff = NULL;
1384
1385 if ( ( compression < 1 ) || ( compression > 9 ) )
1386 return ( NULL );
1387
1388 /* Create the control and data areas */
1389
1390 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1391 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001392 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001393 return ( NULL );
1394 }
1395
1396 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1397 buff->size = INIT_HTTP_BUFF_SIZE;
1398 buff->zbuff = xmlMalloc( buff->size );
1399 if ( buff->zbuff == NULL ) {
1400 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001401 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001402 return ( NULL );
1403 }
1404
1405 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1406 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1407 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001408 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001409 xmlFreeZMemBuff( buff );
1410 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001411 xmlStrPrintf(msg, 500,
1412 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1413 "Error initializing compression context. ZLIB error:",
1414 z_err );
1415 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001416 return ( NULL );
1417 }
1418
1419 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001420 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001421 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1422 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001423 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1424 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1425 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1426 buff->zctrl.avail_out = buff->size - hdr_lgth;
1427
1428 return ( buff );
1429}
1430
1431/**
1432 * xmlZMemBuffExtend
1433 * @buff: Buffer used to compress and consolidate data.
1434 * @ext_amt: Number of bytes to extend the buffer.
1435 *
1436 * Extend the internal buffer used to store the compressed data by the
1437 * specified amount.
1438 *
1439 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1440 * the original buffer still exists at the original size.
1441 */
1442static int
1443xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1444
1445 int rc = -1;
1446 size_t new_size;
1447 size_t cur_used;
1448
1449 unsigned char * tmp_ptr = NULL;
1450
1451 if ( buff == NULL )
1452 return ( -1 );
1453
1454 else if ( ext_amt == 0 )
1455 return ( 0 );
1456
1457 cur_used = buff->zctrl.next_out - buff->zbuff;
1458 new_size = buff->size + ext_amt;
1459
1460#ifdef DEBUG_HTTP
1461 if ( cur_used > new_size )
1462 xmlGenericError( xmlGenericErrorContext,
1463 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1464 "Buffer overwrite detected during compressed memory",
1465 "buffer extension. Overflowed by",
1466 (cur_used - new_size ) );
1467#endif
1468
1469 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1470 if ( tmp_ptr != NULL ) {
1471 rc = 0;
1472 buff->size = new_size;
1473 buff->zbuff = tmp_ptr;
1474 buff->zctrl.next_out = tmp_ptr + cur_used;
1475 buff->zctrl.avail_out = new_size - cur_used;
1476 }
1477 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001478 xmlChar msg[500];
1479 xmlStrPrintf(msg, 500,
1480 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1481 "Allocation failure extending output buffer to",
1482 new_size );
1483 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001484 }
1485
1486 return ( rc );
1487}
1488
1489/**
1490 * xmlZMemBuffAppend
1491 * @buff: Buffer used to compress and consolidate data
1492 * @src: Uncompressed source content to append to buffer
1493 * @len: Length of source data to append to buffer
1494 *
1495 * Compress and append data to the internal buffer. The data buffer
1496 * will be expanded if needed to store the additional data.
1497 *
1498 * Returns the number of bytes appended to the buffer or -1 on error.
1499 */
1500static int
1501xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1502
1503 int z_err;
1504 size_t min_accept;
1505
1506 if ( ( buff == NULL ) || ( src == NULL ) )
1507 return ( -1 );
1508
1509 buff->zctrl.avail_in = len;
1510 buff->zctrl.next_in = (unsigned char *)src;
1511 while ( buff->zctrl.avail_in > 0 ) {
1512 /*
1513 ** Extend the buffer prior to deflate call if a reasonable amount
1514 ** of output buffer space is not available.
1515 */
1516 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1517 if ( buff->zctrl.avail_out <= min_accept ) {
1518 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1519 return ( -1 );
1520 }
1521
1522 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1523 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001524 xmlChar msg[500];
1525 xmlStrPrintf(msg, 500,
1526 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001527 "Compression error while appending",
1528 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001529 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001530 return ( -1 );
1531 }
1532 }
1533
1534 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1535
1536 return ( len );
1537}
1538
1539/**
1540 * xmlZMemBuffGetContent
1541 * @buff: Compressed memory content buffer
1542 * @data_ref: Pointer reference to point to compressed content
1543 *
1544 * Flushes the compression buffers, appends gzip file trailers and
1545 * returns the compressed content and length of the compressed data.
1546 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1547 *
1548 * Returns the length of the compressed data or -1 on error.
1549 */
1550static int
1551xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1552
1553 int zlgth = -1;
1554 int z_err;
1555
1556 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1557 return ( -1 );
1558
1559 /* Need to loop until compression output buffers are flushed */
1560
1561 do
1562 {
1563 z_err = deflate( &buff->zctrl, Z_FINISH );
1564 if ( z_err == Z_OK ) {
1565 /* In this case Z_OK means more buffer space needed */
1566
1567 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1568 return ( -1 );
1569 }
1570 }
1571 while ( z_err == Z_OK );
1572
1573 /* If the compression state is not Z_STREAM_END, some error occurred */
1574
1575 if ( z_err == Z_STREAM_END ) {
1576
1577 /* Need to append the gzip data trailer */
1578
1579 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1580 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1581 return ( -1 );
1582 }
1583
1584 /*
1585 ** For whatever reason, the CRC and length data are pushed out
1586 ** in reverse byte order. So a memcpy can't be used here.
1587 */
1588
1589 append_reverse_ulong( buff, buff->crc );
1590 append_reverse_ulong( buff, buff->zctrl.total_in );
1591
1592 zlgth = buff->zctrl.next_out - buff->zbuff;
1593 *data_ref = (char *)buff->zbuff;
1594 }
1595
Daniel Veillard05d987b2003-10-08 11:54:57 +00001596 else {
1597 xmlChar msg[500];
1598 xmlStrPrintf(msg, 500,
1599 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1600 "Error flushing zlib buffers. Error code", z_err );
1601 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1602 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001603
1604 return ( zlgth );
1605}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001606#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001607#endif /* HAVE_ZLIB_H */
1608
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001609#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001610/**
1611 * xmlFreeHTTPWriteCtxt
1612 * @ctxt: Context to cleanup
1613 *
1614 * Free allocated memory and reclaim system resources.
1615 *
1616 * No return value.
1617 */
1618static void
1619xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1620{
1621 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001622 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001623
1624 if ( ctxt->doc_buff != NULL ) {
1625
1626#ifdef HAVE_ZLIB_H
1627 if ( ctxt->compression > 0 ) {
1628 xmlFreeZMemBuff( ctxt->doc_buff );
1629 }
1630 else
1631#endif
1632 {
1633 xmlOutputBufferClose( ctxt->doc_buff );
1634 }
1635 }
1636
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001637 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001638 return;
1639}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001640#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001641
1642
Owen Taylor3473f882001-02-23 17:55:21 +00001643/**
1644 * xmlIOHTTPMatch:
1645 * @filename: the URI for matching
1646 *
1647 * check if the URI matches an HTTP one
1648 *
1649 * Returns 1 if matches, 0 otherwise
1650 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001651int
Owen Taylor3473f882001-02-23 17:55:21 +00001652xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001653 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001654 return(1);
1655 return(0);
1656}
1657
1658/**
1659 * xmlIOHTTPOpen:
1660 * @filename: the URI for matching
1661 *
1662 * open an HTTP I/O channel
1663 *
1664 * Returns an I/O context or NULL in case of error
1665 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001666void *
Owen Taylor3473f882001-02-23 17:55:21 +00001667xmlIOHTTPOpen (const char *filename) {
1668 return(xmlNanoHTTPOpen(filename, NULL));
1669}
1670
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001671#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001672/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001673 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001674 * @post_uri: The destination URI for the document
1675 * @compression: The compression desired for the document.
1676 *
1677 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1678 * request. Non-static as is called from the output buffer creation routine.
1679 *
1680 * Returns an I/O context or NULL in case of error.
1681 */
1682
1683void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001684xmlIOHTTPOpenW(const char *post_uri, int compression)
1685{
Daniel Veillardf012a642001-07-23 19:10:52 +00001686
Daniel Veillard572577e2002-01-18 16:23:55 +00001687 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001688
Daniel Veillard572577e2002-01-18 16:23:55 +00001689 if (post_uri == NULL)
1690 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001691
Daniel Veillard572577e2002-01-18 16:23:55 +00001692 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1693 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001694 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001695 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001696 }
1697
Daniel Veillard572577e2002-01-18 16:23:55 +00001698 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001699
Daniel Veillard572577e2002-01-18 16:23:55 +00001700 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1701 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001702 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001703 xmlFreeHTTPWriteCtxt(ctxt);
1704 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001705 }
1706
1707 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001708 * ** Since the document length is required for an HTTP post,
1709 * ** need to put the document into a buffer. A memory buffer
1710 * ** is being used to avoid pushing the data to disk and back.
1711 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001712
1713#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001714 if ((compression > 0) && (compression <= 9)) {
1715
1716 ctxt->compression = compression;
1717 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1718 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001719#endif
1720 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001721 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001722
Daniel Veillard572577e2002-01-18 16:23:55 +00001723 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001724 }
1725
Daniel Veillard572577e2002-01-18 16:23:55 +00001726 if (ctxt->doc_buff == NULL) {
1727 xmlFreeHTTPWriteCtxt(ctxt);
1728 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001729 }
1730
Daniel Veillard572577e2002-01-18 16:23:55 +00001731 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001732}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001733#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001734
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001735#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001736/**
1737 * xmlIOHTTPDfltOpenW
1738 * @post_uri: The destination URI for this document.
1739 *
1740 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1741 * HTTP post command. This function should generally not be used as
1742 * the open callback is short circuited in xmlOutputBufferCreateFile.
1743 *
1744 * Returns a pointer to the new IO context.
1745 */
1746static void *
1747xmlIOHTTPDfltOpenW( const char * post_uri ) {
1748 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1749}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001750#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001751
1752/**
Owen Taylor3473f882001-02-23 17:55:21 +00001753 * xmlIOHTTPRead:
1754 * @context: the I/O context
1755 * @buffer: where to drop data
1756 * @len: number of bytes to write
1757 *
1758 * Read @len bytes to @buffer from the I/O channel.
1759 *
1760 * Returns the number of bytes written
1761 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001762int
Owen Taylor3473f882001-02-23 17:55:21 +00001763xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001764 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001765 return(xmlNanoHTTPRead(context, &buffer[0], len));
1766}
1767
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001768#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001769/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001770 * xmlIOHTTPWrite
1771 * @context: previously opened writing context
1772 * @buffer: data to output to temporary buffer
1773 * @len: bytes to output
1774 *
1775 * Collect data from memory buffer into a temporary file for later
1776 * processing.
1777 *
1778 * Returns number of bytes written.
1779 */
1780
1781static int
1782xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1783
1784 xmlIOHTTPWriteCtxtPtr ctxt = context;
1785
1786 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1787 return ( -1 );
1788
1789 if ( len > 0 ) {
1790
1791 /* Use gzwrite or fwrite as previously setup in the open call */
1792
1793#ifdef HAVE_ZLIB_H
1794 if ( ctxt->compression > 0 )
1795 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1796
1797 else
1798#endif
1799 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1800
1801 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001802 xmlChar msg[500];
1803 xmlStrPrintf(msg, 500,
1804 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001805 "Error appending to internal buffer.",
1806 "Error sending document to URI",
1807 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001808 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001809 }
1810 }
1811
1812 return ( len );
1813}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001814#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001815
1816
1817/**
Owen Taylor3473f882001-02-23 17:55:21 +00001818 * xmlIOHTTPClose:
1819 * @context: the I/O context
1820 *
1821 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001822 *
1823 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001824 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001825int
Owen Taylor3473f882001-02-23 17:55:21 +00001826xmlIOHTTPClose (void * context) {
1827 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001828 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001829}
Daniel Veillardf012a642001-07-23 19:10:52 +00001830
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001831#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001832/**
1833 * xmlIOHTTCloseWrite
1834 * @context: The I/O context
1835 * @http_mthd: The HTTP method to be used when sending the data
1836 *
1837 * Close the transmit HTTP I/O channel and actually send the data.
1838 */
1839static int
1840xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1841
1842 int close_rc = -1;
1843 int http_rtn = 0;
1844 int content_lgth = 0;
1845 xmlIOHTTPWriteCtxtPtr ctxt = context;
1846
1847 char * http_content = NULL;
1848 char * content_encoding = NULL;
1849 char * content_type = (char *) "text/xml";
1850 void * http_ctxt = NULL;
1851
1852 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1853 return ( -1 );
1854
1855 /* Retrieve the content from the appropriate buffer */
1856
1857#ifdef HAVE_ZLIB_H
1858
1859 if ( ctxt->compression > 0 ) {
1860 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1861 content_encoding = (char *) "Content-Encoding: gzip";
1862 }
1863 else
1864#endif
1865 {
1866 /* Pull the data out of the memory output buffer */
1867
1868 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1869 http_content = (char *)dctxt->buffer->content;
1870 content_lgth = dctxt->buffer->use;
1871 }
1872
1873 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001874 xmlChar msg[500];
1875 xmlStrPrintf(msg, 500,
1876 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1877 "Error retrieving content.\nUnable to",
1878 http_mthd, "data to URI", ctxt->uri );
1879 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001880 }
1881
1882 else {
1883
1884 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1885 &content_type, content_encoding,
1886 content_lgth );
1887
1888 if ( http_ctxt != NULL ) {
1889#ifdef DEBUG_HTTP
1890 /* If testing/debugging - dump reply with request content */
1891
1892 FILE * tst_file = NULL;
1893 char buffer[ 4096 ];
1894 char * dump_name = NULL;
1895 int avail;
1896
1897 xmlGenericError( xmlGenericErrorContext,
1898 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1899 http_mthd, ctxt->uri,
1900 xmlNanoHTTPReturnCode( http_ctxt ) );
1901
1902 /*
1903 ** Since either content or reply may be gzipped,
1904 ** dump them to separate files instead of the
1905 ** standard error context.
1906 */
1907
1908 dump_name = tempnam( NULL, "lxml" );
1909 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001910 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001911
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001912 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001913 if ( tst_file != NULL ) {
1914 xmlGenericError( xmlGenericErrorContext,
1915 "Transmitted content saved in file: %s\n", buffer );
1916
1917 fwrite( http_content, sizeof( char ),
1918 content_lgth, tst_file );
1919 fclose( tst_file );
1920 }
1921
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001922 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001923 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001924 if ( tst_file != NULL ) {
1925 xmlGenericError( xmlGenericErrorContext,
1926 "Reply content saved in file: %s\n", buffer );
1927
1928
1929 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1930 buffer, sizeof( buffer ) )) > 0 ) {
1931
1932 fwrite( buffer, sizeof( char ), avail, tst_file );
1933 }
1934
1935 fclose( tst_file );
1936 }
1937
1938 free( dump_name );
1939 }
1940#endif /* DEBUG_HTTP */
1941
1942 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1943 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1944 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001945 else {
1946 xmlChar msg[500];
1947 xmlStrPrintf(msg, 500,
1948 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001949 http_mthd, content_lgth,
1950 "bytes to URI", ctxt->uri,
1951 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001952 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1953 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001954
1955 xmlNanoHTTPClose( http_ctxt );
1956 xmlFree( content_type );
1957 }
1958 }
1959
1960 /* Final cleanups */
1961
1962 xmlFreeHTTPWriteCtxt( ctxt );
1963
1964 return ( close_rc );
1965}
1966
1967/**
1968 * xmlIOHTTPClosePut
1969 *
1970 * @context: The I/O context
1971 *
1972 * Close the transmit HTTP I/O channel and actually send data using a PUT
1973 * HTTP method.
1974 */
1975static int
1976xmlIOHTTPClosePut( void * ctxt ) {
1977 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1978}
1979
1980
1981/**
1982 * xmlIOHTTPClosePost
1983 *
1984 * @context: The I/O context
1985 *
1986 * Close the transmit HTTP I/O channel and actually send data using a POST
1987 * HTTP method.
1988 */
1989static int
1990xmlIOHTTPClosePost( void * ctxt ) {
1991 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1992}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001993#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001994
Owen Taylor3473f882001-02-23 17:55:21 +00001995#endif /* LIBXML_HTTP_ENABLED */
1996
1997#ifdef LIBXML_FTP_ENABLED
1998/************************************************************************
1999 * *
2000 * I/O for FTP file accesses *
2001 * *
2002 ************************************************************************/
2003/**
2004 * xmlIOFTPMatch:
2005 * @filename: the URI for matching
2006 *
2007 * check if the URI matches an FTP one
2008 *
2009 * Returns 1 if matches, 0 otherwise
2010 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002011int
Owen Taylor3473f882001-02-23 17:55:21 +00002012xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002013 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002014 return(1);
2015 return(0);
2016}
2017
2018/**
2019 * xmlIOFTPOpen:
2020 * @filename: the URI for matching
2021 *
2022 * open an FTP I/O channel
2023 *
2024 * Returns an I/O context or NULL in case of error
2025 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002026void *
Owen Taylor3473f882001-02-23 17:55:21 +00002027xmlIOFTPOpen (const char *filename) {
2028 return(xmlNanoFTPOpen(filename));
2029}
2030
2031/**
2032 * xmlIOFTPRead:
2033 * @context: the I/O context
2034 * @buffer: where to drop data
2035 * @len: number of bytes to write
2036 *
2037 * Read @len bytes to @buffer from the I/O channel.
2038 *
2039 * Returns the number of bytes written
2040 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002041int
Owen Taylor3473f882001-02-23 17:55:21 +00002042xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002043 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002044 return(xmlNanoFTPRead(context, &buffer[0], len));
2045}
2046
2047/**
2048 * xmlIOFTPClose:
2049 * @context: the I/O context
2050 *
2051 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002052 *
2053 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002054 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002055int
Owen Taylor3473f882001-02-23 17:55:21 +00002056xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002057 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002058}
2059#endif /* LIBXML_FTP_ENABLED */
2060
2061
2062/**
2063 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002064 * @matchFunc: the xmlInputMatchCallback
2065 * @openFunc: the xmlInputOpenCallback
2066 * @readFunc: the xmlInputReadCallback
2067 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002068 *
2069 * Register a new set of I/O callback for handling parser input.
2070 *
2071 * Returns the registered handler number or -1 in case of error
2072 */
2073int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002074xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2075 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2076 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002077 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2078 return(-1);
2079 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002080 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2081 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2082 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2083 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002084 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002085 return(xmlInputCallbackNr++);
2086}
2087
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002088#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002089/**
2090 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002091 * @matchFunc: the xmlOutputMatchCallback
2092 * @openFunc: the xmlOutputOpenCallback
2093 * @writeFunc: the xmlOutputWriteCallback
2094 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002095 *
2096 * Register a new set of I/O callback for handling output.
2097 *
2098 * Returns the registered handler number or -1 in case of error
2099 */
2100int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002101xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2102 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2103 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002104 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
2105 return(-1);
2106 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002107 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2108 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2109 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2110 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002111 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002112 return(xmlOutputCallbackNr++);
2113}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002114#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002115
2116/**
2117 * xmlRegisterDefaultInputCallbacks:
2118 *
2119 * Registers the default compiled-in I/O handlers.
2120 */
2121void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002122xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002123 if (xmlInputCallbackInitialized)
2124 return;
2125
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002126#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2127 xmlInitPlatformSpecificIo();
2128#endif
2129
Owen Taylor3473f882001-02-23 17:55:21 +00002130 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2131 xmlFileRead, xmlFileClose);
2132#ifdef HAVE_ZLIB_H
2133 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2134 xmlGzfileRead, xmlGzfileClose);
2135#endif /* HAVE_ZLIB_H */
2136
2137#ifdef LIBXML_HTTP_ENABLED
2138 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2139 xmlIOHTTPRead, xmlIOHTTPClose);
2140#endif /* LIBXML_HTTP_ENABLED */
2141
2142#ifdef LIBXML_FTP_ENABLED
2143 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2144 xmlIOFTPRead, xmlIOFTPClose);
2145#endif /* LIBXML_FTP_ENABLED */
2146 xmlInputCallbackInitialized = 1;
2147}
2148
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002149#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002150/**
2151 * xmlRegisterDefaultOutputCallbacks:
2152 *
2153 * Registers the default compiled-in I/O handlers.
2154 */
2155void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002156xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002157 if (xmlOutputCallbackInitialized)
2158 return;
2159
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002160#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2161 xmlInitPlatformSpecificIo();
2162#endif
2163
Owen Taylor3473f882001-02-23 17:55:21 +00002164 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2165 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002166
2167#ifdef LIBXML_HTTP_ENABLED
2168 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2169 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2170#endif
2171
Owen Taylor3473f882001-02-23 17:55:21 +00002172/*********************************
2173 No way a-priori to distinguish between gzipped files from
2174 uncompressed ones except opening if existing then closing
2175 and saving with same compression ratio ... a pain.
2176
2177#ifdef HAVE_ZLIB_H
2178 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2179 xmlGzfileWrite, xmlGzfileClose);
2180#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002181
2182 Nor FTP PUT ....
2183#ifdef LIBXML_FTP_ENABLED
2184 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2185 xmlIOFTPWrite, xmlIOFTPClose);
2186#endif
2187 **********************************/
2188 xmlOutputCallbackInitialized = 1;
2189}
2190
Daniel Veillardf012a642001-07-23 19:10:52 +00002191#ifdef LIBXML_HTTP_ENABLED
2192/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002193 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002194 *
2195 * By default, libxml submits HTTP output requests using the "PUT" method.
2196 * Calling this method changes the HTTP output method to use the "POST"
2197 * method instead.
2198 *
2199 */
2200void
2201xmlRegisterHTTPPostCallbacks( void ) {
2202
2203 /* Register defaults if not done previously */
2204
2205 if ( xmlOutputCallbackInitialized == 0 )
2206 xmlRegisterDefaultOutputCallbacks( );
2207
2208 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2209 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2210 return;
2211}
2212#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002213#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002214
Owen Taylor3473f882001-02-23 17:55:21 +00002215/**
2216 * xmlAllocParserInputBuffer:
2217 * @enc: the charset encoding if known
2218 *
2219 * Create a buffered parser input for progressive parsing
2220 *
2221 * Returns the new parser input or NULL
2222 */
2223xmlParserInputBufferPtr
2224xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2225 xmlParserInputBufferPtr ret;
2226
2227 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2228 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002229 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002230 return(NULL);
2231 }
2232 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002233 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002234 if (ret->buffer == NULL) {
2235 xmlFree(ret);
2236 return(NULL);
2237 }
2238 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2239 ret->encoder = xmlGetCharEncodingHandler(enc);
2240 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002241 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002242 else
2243 ret->raw = NULL;
2244 ret->readcallback = NULL;
2245 ret->closecallback = NULL;
2246 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002247 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002248 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002249
2250 return(ret);
2251}
2252
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002253#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002254/**
2255 * xmlAllocOutputBuffer:
2256 * @encoder: the encoding converter or NULL
2257 *
2258 * Create a buffered parser output
2259 *
2260 * Returns the new parser output or NULL
2261 */
2262xmlOutputBufferPtr
2263xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2264 xmlOutputBufferPtr ret;
2265
2266 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2267 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002268 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002269 return(NULL);
2270 }
2271 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2272 ret->buffer = xmlBufferCreate();
2273 if (ret->buffer == NULL) {
2274 xmlFree(ret);
2275 return(NULL);
2276 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002277
2278 /*
2279 * For conversion buffers we use the special IO handling
2280 */
2281 ret->buffer->alloc = XML_BUFFER_ALLOC_IO;
2282 ret->buffer->contentIO = ret->buffer->content;
2283
Owen Taylor3473f882001-02-23 17:55:21 +00002284 ret->encoder = encoder;
2285 if (encoder != NULL) {
2286 ret->conv = xmlBufferCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002287 if (ret->conv == NULL) {
2288 xmlFree(ret);
2289 return(NULL);
2290 }
2291
Owen Taylor3473f882001-02-23 17:55:21 +00002292 /*
2293 * This call is designed to initiate the encoder state
2294 */
2295 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2296 } else
2297 ret->conv = NULL;
2298 ret->writecallback = NULL;
2299 ret->closecallback = NULL;
2300 ret->context = NULL;
2301 ret->written = 0;
2302
2303 return(ret);
2304}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002305#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002306
2307/**
2308 * xmlFreeParserInputBuffer:
2309 * @in: a buffered parser input
2310 *
2311 * Free up the memory used by a buffered parser input
2312 */
2313void
2314xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002315 if (in == NULL) return;
2316
Owen Taylor3473f882001-02-23 17:55:21 +00002317 if (in->raw) {
2318 xmlBufferFree(in->raw);
2319 in->raw = NULL;
2320 }
2321 if (in->encoder != NULL) {
2322 xmlCharEncCloseFunc(in->encoder);
2323 }
2324 if (in->closecallback != NULL) {
2325 in->closecallback(in->context);
2326 }
2327 if (in->buffer != NULL) {
2328 xmlBufferFree(in->buffer);
2329 in->buffer = NULL;
2330 }
2331
Owen Taylor3473f882001-02-23 17:55:21 +00002332 xmlFree(in);
2333}
2334
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002335#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002336/**
2337 * xmlOutputBufferClose:
2338 * @out: a buffered output
2339 *
2340 * flushes and close the output I/O channel
2341 * and free up all the associated resources
2342 *
2343 * Returns the number of byte written or -1 in case of error.
2344 */
2345int
Daniel Veillard828ce832003-10-08 19:19:10 +00002346xmlOutputBufferClose(xmlOutputBufferPtr out)
2347{
Owen Taylor3473f882001-02-23 17:55:21 +00002348 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002349 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002350
2351 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002352 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002353 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002354 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002355 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002356 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002357 }
2358 written = out->written;
2359 if (out->conv) {
2360 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002361 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002362 }
2363 if (out->encoder != NULL) {
2364 xmlCharEncCloseFunc(out->encoder);
2365 }
2366 if (out->buffer != NULL) {
2367 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002368 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002369 }
2370
Daniel Veillard828ce832003-10-08 19:19:10 +00002371 if (out->error)
2372 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002373 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002374 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002375}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002376#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002377
Daniel Veillard1b243b42004-06-08 10:16:42 +00002378xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002379__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002380 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002381 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002382 void *context = NULL;
2383
2384 if (xmlInputCallbackInitialized == 0)
2385 xmlRegisterDefaultInputCallbacks();
2386
2387 if (URI == NULL) return(NULL);
2388
2389 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002390 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002391 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002392 */
2393 if (context == NULL) {
2394 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2395 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2396 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002397 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002398 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002399 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002400 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002401 }
Owen Taylor3473f882001-02-23 17:55:21 +00002402 }
2403 }
2404 if (context == NULL) {
2405 return(NULL);
2406 }
2407
2408 /*
2409 * Allocate the Input buffer front-end.
2410 */
2411 ret = xmlAllocParserInputBuffer(enc);
2412 if (ret != NULL) {
2413 ret->context = context;
2414 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2415 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002416#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002417 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2418 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002419 if (((z_stream *)context)->avail_in > 4) {
2420 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002421 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002422 if (gzread(context, buff4, 4) == 4) {
2423 if (strncmp(buff4, cptr, 4) == 0)
2424 ret->compressed = 0;
2425 else
2426 ret->compressed = 1;
2427 gzrewind(context);
2428 }
2429 }
2430 }
2431#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002432 }
William M. Brack42331a92004-07-29 07:07:16 +00002433 else
2434 xmlInputCallbackTable[i].closecallback (context);
2435
Owen Taylor3473f882001-02-23 17:55:21 +00002436 return(ret);
2437}
2438
2439/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002440 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002441 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002442 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002443 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002444 * Create a buffered parser input for the progressive parsing of a file
2445 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002446 * Automatic support for ZLIB/Compress compressed document is provided
2447 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002448 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002449 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002450 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002451 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002452xmlParserInputBufferPtr
2453xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2454 if ((xmlParserInputBufferCreateFilenameValue)) {
2455 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2456 }
2457 return __xmlParserInputBufferCreateFilename(URI, enc);
2458}
2459
2460#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002461xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002462__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002463 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002464 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002465 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002466 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002467 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002468 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002469 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002470#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002471 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002472#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002473
Owen Taylor3473f882001-02-23 17:55:21 +00002474 if (xmlOutputCallbackInitialized == 0)
2475 xmlRegisterDefaultOutputCallbacks();
2476
2477 if (URI == NULL) return(NULL);
2478
Daniel Veillard966a31e2004-05-09 02:58:44 +00002479 puri = xmlParseURI(URI);
2480 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002481#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002482 if ((puri->scheme != NULL) &&
2483 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002484 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002485#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002486 /*
2487 * try to limit the damages of the URI unescaping code.
2488 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002489 if ((puri->scheme == NULL) ||
2490 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002491 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2492 xmlFreeURI(puri);
2493 }
Owen Taylor3473f882001-02-23 17:55:21 +00002494
2495 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002496 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002497 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002498 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002499 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002500 if (unescaped != NULL) {
2501#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002502 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002503 context = xmlGzfileOpenW(unescaped, compression);
2504 if (context != NULL) {
2505 ret = xmlAllocOutputBuffer(encoder);
2506 if (ret != NULL) {
2507 ret->context = context;
2508 ret->writecallback = xmlGzfileWrite;
2509 ret->closecallback = xmlGzfileClose;
2510 }
2511 xmlFree(unescaped);
2512 return(ret);
2513 }
2514 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002515#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002516 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2517 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2518 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2519#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2520 /* Need to pass compression parameter into HTTP open calls */
2521 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2522 context = xmlIOHTTPOpenW(unescaped, compression);
2523 else
2524#endif
2525 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2526 if (context != NULL)
2527 break;
2528 }
2529 }
2530 xmlFree(unescaped);
2531 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002532
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002533 /*
2534 * If this failed try with a non-escaped URI this may be a strange
2535 * filename
2536 */
2537 if (context == NULL) {
2538#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002539 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002540 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002541 if (context != NULL) {
2542 ret = xmlAllocOutputBuffer(encoder);
2543 if (ret != NULL) {
2544 ret->context = context;
2545 ret->writecallback = xmlGzfileWrite;
2546 ret->closecallback = xmlGzfileClose;
2547 }
2548 return(ret);
2549 }
2550 }
2551#endif
2552 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2553 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002554 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002555#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2556 /* Need to pass compression parameter into HTTP open calls */
2557 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2558 context = xmlIOHTTPOpenW(URI, compression);
2559 else
2560#endif
2561 context = xmlOutputCallbackTable[i].opencallback(URI);
2562 if (context != NULL)
2563 break;
2564 }
Owen Taylor3473f882001-02-23 17:55:21 +00002565 }
2566 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002567
Owen Taylor3473f882001-02-23 17:55:21 +00002568 if (context == NULL) {
2569 return(NULL);
2570 }
2571
2572 /*
2573 * Allocate the Output buffer front-end.
2574 */
2575 ret = xmlAllocOutputBuffer(encoder);
2576 if (ret != NULL) {
2577 ret->context = context;
2578 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2579 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2580 }
2581 return(ret);
2582}
Daniel Veillard0335a842004-06-02 16:18:40 +00002583
2584/**
2585 * xmlOutputBufferCreateFilename:
2586 * @URI: a C string containing the URI or filename
2587 * @encoder: the encoding converter or NULL
2588 * @compression: the compression ration (0 none, 9 max).
2589 *
2590 * Create a buffered output for the progressive saving of a file
2591 * If filename is "-' then we use stdout as the output.
2592 * Automatic support for ZLIB/Compress compressed document is provided
2593 * by default if found at compile-time.
2594 * TODO: currently if compression is set, the library only support
2595 * writing to a local file.
2596 *
2597 * Returns the new output or NULL
2598 */
2599xmlOutputBufferPtr
2600xmlOutputBufferCreateFilename(const char *URI,
2601 xmlCharEncodingHandlerPtr encoder,
2602 int compression ATTRIBUTE_UNUSED) {
2603 if ((xmlOutputBufferCreateFilenameValue)) {
2604 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2605 }
2606 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2607}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002608#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002609
2610/**
2611 * xmlParserInputBufferCreateFile:
2612 * @file: a FILE*
2613 * @enc: the charset encoding if known
2614 *
2615 * Create a buffered parser input for the progressive parsing of a FILE *
2616 * buffered C I/O
2617 *
2618 * Returns the new parser input or NULL
2619 */
2620xmlParserInputBufferPtr
2621xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2622 xmlParserInputBufferPtr ret;
2623
2624 if (xmlInputCallbackInitialized == 0)
2625 xmlRegisterDefaultInputCallbacks();
2626
2627 if (file == NULL) return(NULL);
2628
2629 ret = xmlAllocParserInputBuffer(enc);
2630 if (ret != NULL) {
2631 ret->context = file;
2632 ret->readcallback = xmlFileRead;
2633 ret->closecallback = xmlFileFlush;
2634 }
2635
2636 return(ret);
2637}
2638
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002639#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002640/**
2641 * xmlOutputBufferCreateFile:
2642 * @file: a FILE*
2643 * @encoder: the encoding converter or NULL
2644 *
2645 * Create a buffered output for the progressive saving to a FILE *
2646 * buffered C I/O
2647 *
2648 * Returns the new parser output or NULL
2649 */
2650xmlOutputBufferPtr
2651xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2652 xmlOutputBufferPtr ret;
2653
2654 if (xmlOutputCallbackInitialized == 0)
2655 xmlRegisterDefaultOutputCallbacks();
2656
2657 if (file == NULL) return(NULL);
2658
2659 ret = xmlAllocOutputBuffer(encoder);
2660 if (ret != NULL) {
2661 ret->context = file;
2662 ret->writecallback = xmlFileWrite;
2663 ret->closecallback = xmlFileFlush;
2664 }
2665
2666 return(ret);
2667}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002668
2669/**
2670 * xmlOutputBufferCreateBuffer:
2671 * @buffer: a xmlBufferPtr
2672 * @encoder: the encoding converter or NULL
2673 *
2674 * Create a buffered output for the progressive saving to a xmlBuffer
2675 *
2676 * Returns the new parser output or NULL
2677 */
2678xmlOutputBufferPtr
2679xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2680 xmlCharEncodingHandlerPtr encoder) {
2681 xmlOutputBufferPtr ret;
2682
2683 if (buffer == NULL) return(NULL);
2684
Rob Richardsa44f2342005-11-09 18:03:45 +00002685 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2686 xmlBufferWrite,
2687 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002688 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002689
2690 return(ret);
2691}
2692
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002693#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002694
2695/**
2696 * xmlParserInputBufferCreateFd:
2697 * @fd: a file descriptor number
2698 * @enc: the charset encoding if known
2699 *
2700 * Create a buffered parser input for the progressive parsing for the input
2701 * from a file descriptor
2702 *
2703 * Returns the new parser input or NULL
2704 */
2705xmlParserInputBufferPtr
2706xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2707 xmlParserInputBufferPtr ret;
2708
2709 if (fd < 0) return(NULL);
2710
2711 ret = xmlAllocParserInputBuffer(enc);
2712 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002713 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002714 ret->readcallback = xmlFdRead;
2715 ret->closecallback = xmlFdClose;
2716 }
2717
2718 return(ret);
2719}
2720
2721/**
2722 * xmlParserInputBufferCreateMem:
2723 * @mem: the memory input
2724 * @size: the length of the memory block
2725 * @enc: the charset encoding if known
2726 *
2727 * Create a buffered parser input for the progressive parsing for the input
2728 * from a memory area.
2729 *
2730 * Returns the new parser input or NULL
2731 */
2732xmlParserInputBufferPtr
2733xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2734 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002735 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002736
2737 if (size <= 0) return(NULL);
2738 if (mem == NULL) return(NULL);
2739
2740 ret = xmlAllocParserInputBuffer(enc);
2741 if (ret != NULL) {
2742 ret->context = (void *) mem;
2743 ret->readcallback = (xmlInputReadCallback) xmlNop;
2744 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002745 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2746 if (errcode != 0) {
2747 xmlFree(ret);
2748 return(NULL);
2749 }
Owen Taylor3473f882001-02-23 17:55:21 +00002750 }
2751
2752 return(ret);
2753}
2754
2755/**
Daniel Veillard53350552003-09-18 13:35:51 +00002756 * xmlParserInputBufferCreateStatic:
2757 * @mem: the memory input
2758 * @size: the length of the memory block
2759 * @enc: the charset encoding if known
2760 *
2761 * Create a buffered parser input for the progressive parsing for the input
2762 * from an immutable memory area. This will not copy the memory area to
2763 * the buffer, but the memory is expected to be available until the end of
2764 * the parsing, this is useful for example when using mmap'ed file.
2765 *
2766 * Returns the new parser input or NULL
2767 */
2768xmlParserInputBufferPtr
2769xmlParserInputBufferCreateStatic(const char *mem, int size,
2770 xmlCharEncoding enc) {
2771 xmlParserInputBufferPtr ret;
2772
2773 if (size <= 0) return(NULL);
2774 if (mem == NULL) return(NULL);
2775
2776 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2777 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002778 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002779 return(NULL);
2780 }
2781 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002782 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002783 if (ret->buffer == NULL) {
2784 xmlFree(ret);
2785 return(NULL);
2786 }
2787 ret->encoder = xmlGetCharEncodingHandler(enc);
2788 if (ret->encoder != NULL)
2789 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2790 else
2791 ret->raw = NULL;
2792 ret->compressed = -1;
2793 ret->context = (void *) mem;
2794 ret->readcallback = NULL;
2795 ret->closecallback = NULL;
2796
2797 return(ret);
2798}
2799
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002800#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002801/**
Owen Taylor3473f882001-02-23 17:55:21 +00002802 * xmlOutputBufferCreateFd:
2803 * @fd: a file descriptor number
2804 * @encoder: the encoding converter or NULL
2805 *
2806 * Create a buffered output for the progressive saving
2807 * to a file descriptor
2808 *
2809 * Returns the new parser output or NULL
2810 */
2811xmlOutputBufferPtr
2812xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2813 xmlOutputBufferPtr ret;
2814
2815 if (fd < 0) return(NULL);
2816
2817 ret = xmlAllocOutputBuffer(encoder);
2818 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002819 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002820 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002821 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002822 }
2823
2824 return(ret);
2825}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002826#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002827
2828/**
2829 * xmlParserInputBufferCreateIO:
2830 * @ioread: an I/O read function
2831 * @ioclose: an I/O close function
2832 * @ioctx: an I/O handler
2833 * @enc: the charset encoding if known
2834 *
2835 * Create a buffered parser input for the progressive parsing for the input
2836 * from an I/O handler
2837 *
2838 * Returns the new parser input or NULL
2839 */
2840xmlParserInputBufferPtr
2841xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2842 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2843 xmlParserInputBufferPtr ret;
2844
2845 if (ioread == NULL) return(NULL);
2846
2847 ret = xmlAllocParserInputBuffer(enc);
2848 if (ret != NULL) {
2849 ret->context = (void *) ioctx;
2850 ret->readcallback = ioread;
2851 ret->closecallback = ioclose;
2852 }
2853
2854 return(ret);
2855}
2856
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002857#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002858/**
2859 * xmlOutputBufferCreateIO:
2860 * @iowrite: an I/O write function
2861 * @ioclose: an I/O close function
2862 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002863 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002864 *
2865 * Create a buffered output for the progressive saving
2866 * to an I/O handler
2867 *
2868 * Returns the new parser output or NULL
2869 */
2870xmlOutputBufferPtr
2871xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2872 xmlOutputCloseCallback ioclose, void *ioctx,
2873 xmlCharEncodingHandlerPtr encoder) {
2874 xmlOutputBufferPtr ret;
2875
2876 if (iowrite == NULL) return(NULL);
2877
2878 ret = xmlAllocOutputBuffer(encoder);
2879 if (ret != NULL) {
2880 ret->context = (void *) ioctx;
2881 ret->writecallback = iowrite;
2882 ret->closecallback = ioclose;
2883 }
2884
2885 return(ret);
2886}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002887#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002888
2889/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002890 * xmlParserInputBufferCreateFilenameDefault:
2891 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2892 *
2893 * Registers a callback for URI input file handling
2894 *
2895 * Returns the old value of the registration function
2896 */
2897xmlParserInputBufferCreateFilenameFunc
2898xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2899{
2900 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2901 if (old == NULL) {
2902 old = __xmlParserInputBufferCreateFilename;
2903 }
2904
2905 xmlParserInputBufferCreateFilenameValue = func;
2906 return(old);
2907}
2908
2909/**
2910 * xmlOutputBufferCreateFilenameDefault:
2911 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2912 *
2913 * Registers a callback for URI output file handling
2914 *
2915 * Returns the old value of the registration function
2916 */
2917xmlOutputBufferCreateFilenameFunc
2918xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2919{
2920 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2921#ifdef LIBXML_OUTPUT_ENABLED
2922 if (old == NULL) {
2923 old = __xmlOutputBufferCreateFilename;
2924 }
2925#endif
2926 xmlOutputBufferCreateFilenameValue = func;
2927 return(old);
2928}
2929
2930/**
Owen Taylor3473f882001-02-23 17:55:21 +00002931 * xmlParserInputBufferPush:
2932 * @in: a buffered parser input
2933 * @len: the size in bytes of the array.
2934 * @buf: an char array
2935 *
2936 * Push the content of the arry in the input buffer
2937 * This routine handle the I18N transcoding to internal UTF-8
2938 * This is used when operating the parser in progressive (push) mode.
2939 *
2940 * Returns the number of chars read and stored in the buffer, or -1
2941 * in case of error.
2942 */
2943int
2944xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2945 int len, const char *buf) {
2946 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002947 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002948
2949 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002950 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002951 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002952 unsigned int use;
2953
Owen Taylor3473f882001-02-23 17:55:21 +00002954 /*
2955 * Store the data in the incoming raw buffer
2956 */
2957 if (in->raw == NULL) {
2958 in->raw = xmlBufferCreate();
2959 }
William M. Bracka3215c72004-07-31 16:24:01 +00002960 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2961 if (ret != 0)
2962 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002963
2964 /*
2965 * convert as much as possible to the parser reading buffer.
2966 */
Daniel Veillard36711902004-02-11 13:25:26 +00002967 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002968 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2969 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002970 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002971 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002972 return(-1);
2973 }
Daniel Veillard36711902004-02-11 13:25:26 +00002974 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002975 } else {
2976 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002977 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2978 if (ret != 0)
2979 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002980 }
2981#ifdef DEBUG_INPUT
2982 xmlGenericError(xmlGenericErrorContext,
2983 "I/O: pushed %d chars, buffer %d/%d\n",
2984 nbchars, in->buffer->use, in->buffer->size);
2985#endif
2986 return(nbchars);
2987}
2988
2989/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002990 * endOfInput:
2991 *
2992 * When reading from an Input channel indicated end of file or error
2993 * don't reread from it again.
2994 */
2995static int
2996endOfInput (void * context ATTRIBUTE_UNUSED,
2997 char * buffer ATTRIBUTE_UNUSED,
2998 int len ATTRIBUTE_UNUSED) {
2999 return(0);
3000}
3001
3002/**
Owen Taylor3473f882001-02-23 17:55:21 +00003003 * xmlParserInputBufferGrow:
3004 * @in: a buffered parser input
3005 * @len: indicative value of the amount of chars to read
3006 *
3007 * Grow up the content of the input buffer, the old data are preserved
3008 * This routine handle the I18N transcoding to internal UTF-8
3009 * This routine is used when operating the parser in normal (pull) mode
3010 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003011 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003012 * onto in->buffer or in->raw
3013 *
3014 * Returns the number of chars read and stored in the buffer, or -1
3015 * in case of error.
3016 */
3017int
3018xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3019 char *buffer = NULL;
3020 int res = 0;
3021 int nbchars = 0;
3022 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00003023 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00003024
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003025 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003026 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003027 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003028
Owen Taylor3473f882001-02-23 17:55:21 +00003029 buffree = in->buffer->size - in->buffer->use;
3030 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003031 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003032 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003033 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003034 }
Owen Taylor3473f882001-02-23 17:55:21 +00003035
Daniel Veillarde5354492002-05-16 08:43:22 +00003036 needSize = in->buffer->use + len + 1;
3037 if (needSize > in->buffer->size){
3038 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003039 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003040 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003041 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003042 }
Owen Taylor3473f882001-02-23 17:55:21 +00003043 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003044 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003045
3046 /*
3047 * Call the read method for this I/O type.
3048 */
3049 if (in->readcallback != NULL) {
3050 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003051 if (res <= 0)
3052 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003053 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003054 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003055 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003056 return(-1);
3057 }
3058 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003059 return(-1);
3060 }
3061 len = res;
3062 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003063 unsigned int use;
3064
Owen Taylor3473f882001-02-23 17:55:21 +00003065 /*
3066 * Store the data in the incoming raw buffer
3067 */
3068 if (in->raw == NULL) {
3069 in->raw = xmlBufferCreate();
3070 }
William M. Bracka3215c72004-07-31 16:24:01 +00003071 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3072 if (res != 0)
3073 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003074
3075 /*
3076 * convert as much as possible to the parser reading buffer.
3077 */
Daniel Veillard36711902004-02-11 13:25:26 +00003078 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003079 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3080 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003081 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003082 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003083 return(-1);
3084 }
Daniel Veillard36711902004-02-11 13:25:26 +00003085 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003086 } else {
3087 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00003088 in->buffer->use += nbchars;
3089 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003090 }
3091#ifdef DEBUG_INPUT
3092 xmlGenericError(xmlGenericErrorContext,
3093 "I/O: read %d chars, buffer %d/%d\n",
3094 nbchars, in->buffer->use, in->buffer->size);
3095#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003096 return(nbchars);
3097}
3098
3099/**
3100 * xmlParserInputBufferRead:
3101 * @in: a buffered parser input
3102 * @len: indicative value of the amount of chars to read
3103 *
3104 * Refresh the content of the input buffer, the old data are considered
3105 * consumed
3106 * This routine handle the I18N transcoding to internal UTF-8
3107 *
3108 * Returns the number of chars read and stored in the buffer, or -1
3109 * in case of error.
3110 */
3111int
3112xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003113 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003114 if (in->readcallback != NULL)
3115 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003116 else if ((in->buffer != NULL) &&
3117 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3118 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003119 else
3120 return(-1);
3121}
3122
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003123#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003124/**
3125 * xmlOutputBufferWrite:
3126 * @out: a buffered parser output
3127 * @len: the size in bytes of the array.
3128 * @buf: an char array
3129 *
3130 * Write the content of the array in the output I/O buffer
3131 * This routine handle the I18N transcoding from internal UTF-8
3132 * The buffer is lossless, i.e. will store in case of partial
3133 * or delayed writes.
3134 *
3135 * Returns the number of chars immediately written, or -1
3136 * in case of error.
3137 */
3138int
3139xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3140 int nbchars = 0; /* number of chars to output to I/O */
3141 int ret; /* return from function call */
3142 int written = 0; /* number of char written to I/O so far */
3143 int chunk; /* number of byte curreent processed from buf */
3144
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003145 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003146 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003147 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003148
3149 do {
3150 chunk = len;
3151 if (chunk > 4 * MINLEN)
3152 chunk = 4 * MINLEN;
3153
3154 /*
3155 * first handle encoding stuff.
3156 */
3157 if (out->encoder != NULL) {
3158 /*
3159 * Store the data in the incoming raw buffer
3160 */
3161 if (out->conv == NULL) {
3162 out->conv = xmlBufferCreate();
3163 }
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
3168 if ((out->buffer->use < MINLEN) && (chunk == len))
3169 goto done;
3170
3171 /*
3172 * convert as much as possible to the parser reading buffer.
3173 */
3174 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003175 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003176 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003177 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003178 return(-1);
3179 }
3180 nbchars = out->conv->use;
3181 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003182 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3183 if (ret != 0)
3184 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003185 nbchars = out->buffer->use;
3186 }
3187 buf += chunk;
3188 len -= chunk;
3189
3190 if ((nbchars < MINLEN) && (len <= 0))
3191 goto done;
3192
3193 if (out->writecallback) {
3194 /*
3195 * second write the stuff to the I/O channel
3196 */
3197 if (out->encoder != NULL) {
3198 ret = out->writecallback(out->context,
3199 (const char *)out->conv->content, nbchars);
3200 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003201 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003202 } else {
3203 ret = out->writecallback(out->context,
3204 (const char *)out->buffer->content, nbchars);
3205 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003206 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003207 }
3208 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003209 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003210 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003211 return(ret);
3212 }
3213 out->written += ret;
3214 }
3215 written += nbchars;
3216 } while (len > 0);
3217
3218done:
3219#ifdef DEBUG_INPUT
3220 xmlGenericError(xmlGenericErrorContext,
3221 "I/O: wrote %d chars\n", written);
3222#endif
3223 return(written);
3224}
3225
3226/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003227 * xmlEscapeContent:
3228 * @out: a pointer to an array of bytes to store the result
3229 * @outlen: the length of @out
3230 * @in: a pointer to an array of unescaped UTF-8 bytes
3231 * @inlen: the length of @in
3232 *
3233 * Take a block of UTF-8 chars in and escape them.
3234 * Returns 0 if success, or -1 otherwise
3235 * The value of @inlen after return is the number of octets consumed
3236 * if the return value is positive, else unpredictable.
3237 * The value of @outlen after return is the number of octets consumed.
3238 */
3239static int
3240xmlEscapeContent(unsigned char* out, int *outlen,
3241 const xmlChar* in, int *inlen) {
3242 unsigned char* outstart = out;
3243 const unsigned char* base = in;
3244 unsigned char* outend = out + *outlen;
3245 const unsigned char* inend;
3246
3247 inend = in + (*inlen);
3248
3249 while ((in < inend) && (out < outend)) {
3250 if (*in == '<') {
3251 if (outend - out < 4) break;
3252 *out++ = '&';
3253 *out++ = 'l';
3254 *out++ = 't';
3255 *out++ = ';';
3256 } else if (*in == '>') {
3257 if (outend - out < 4) break;
3258 *out++ = '&';
3259 *out++ = 'g';
3260 *out++ = 't';
3261 *out++ = ';';
3262 } else if (*in == '&') {
3263 if (outend - out < 5) break;
3264 *out++ = '&';
3265 *out++ = 'a';
3266 *out++ = 'm';
3267 *out++ = 'p';
3268 *out++ = ';';
3269 } else if (*in == '\r') {
3270 if (outend - out < 5) break;
3271 *out++ = '&';
3272 *out++ = '#';
3273 *out++ = '1';
3274 *out++ = '3';
3275 *out++ = ';';
3276 } else {
3277 *out++ = (unsigned char) *in;
3278 }
3279 ++in;
3280 }
3281 *outlen = out - outstart;
3282 *inlen = in - base;
3283 return(0);
3284}
3285
3286/**
3287 * xmlOutputBufferWriteEscape:
3288 * @out: a buffered parser output
3289 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003290 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003291 *
3292 * Write the content of the string in the output I/O buffer
3293 * This routine escapes the caracters and then handle the I18N
3294 * transcoding from internal UTF-8
3295 * The buffer is lossless, i.e. will store in case of partial
3296 * or delayed writes.
3297 *
3298 * Returns the number of chars immediately written, or -1
3299 * in case of error.
3300 */
3301int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003302xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3303 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003304 int nbchars = 0; /* number of chars to output to I/O */
3305 int ret; /* return from function call */
3306 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003307 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003308 int chunk; /* number of byte currently processed from str */
3309 int len; /* number of bytes in str */
3310 int cons; /* byte from str consumed */
3311
Daniel Veillardce244ad2004-11-05 10:03:46 +00003312 if ((out == NULL) || (out->error) || (str == NULL) ||
3313 (out->buffer == NULL) ||
3314 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003315 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003316 if (len < 0) return(0);
3317 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003318 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003319
3320 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003321 oldwritten = written;
3322
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003323 /*
3324 * how many bytes to consume and how many bytes to store.
3325 */
3326 cons = len;
3327 chunk = (out->buffer->size - out->buffer->use) - 1;
3328
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003329 /*
3330 * make sure we have enough room to save first, if this is
3331 * not the case force a flush, but make sure we stay in the loop
3332 */
3333 if (chunk < 40) {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003334 if (xmlBufferGrow(out->buffer, out->buffer->size + 100) < 0)
3335 return(-1);
3336 oldwritten = -1;
3337 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003338 }
3339
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003340 /*
3341 * first handle encoding stuff.
3342 */
3343 if (out->encoder != NULL) {
3344 /*
3345 * Store the data in the incoming raw buffer
3346 */
3347 if (out->conv == NULL) {
3348 out->conv = xmlBufferCreate();
3349 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003350 ret = escaping(out->buffer->content + out->buffer->use ,
3351 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003352 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003353 return(-1);
3354 out->buffer->use += chunk;
3355 out->buffer->content[out->buffer->use] = 0;
3356
3357 if ((out->buffer->use < MINLEN) && (cons == len))
3358 goto done;
3359
3360 /*
3361 * convert as much as possible to the output buffer.
3362 */
3363 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3364 if ((ret < 0) && (ret != -3)) {
3365 xmlIOErr(XML_IO_ENCODER, NULL);
3366 out->error = XML_IO_ENCODER;
3367 return(-1);
3368 }
3369 nbchars = out->conv->use;
3370 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003371 ret = escaping(out->buffer->content + out->buffer->use ,
3372 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003373 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003374 return(-1);
3375 out->buffer->use += chunk;
3376 out->buffer->content[out->buffer->use] = 0;
3377 nbchars = out->buffer->use;
3378 }
3379 str += cons;
3380 len -= cons;
3381
3382 if ((nbchars < MINLEN) && (len <= 0))
3383 goto done;
3384
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003385flush:
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003386 if (out->writecallback) {
3387 /*
3388 * second write the stuff to the I/O channel
3389 */
3390 if (out->encoder != NULL) {
3391 ret = out->writecallback(out->context,
3392 (const char *)out->conv->content, nbchars);
3393 if (ret >= 0)
3394 xmlBufferShrink(out->conv, ret);
3395 } else {
3396 ret = out->writecallback(out->context,
3397 (const char *)out->buffer->content, nbchars);
3398 if (ret >= 0)
3399 xmlBufferShrink(out->buffer, ret);
3400 }
3401 if (ret < 0) {
3402 xmlIOErr(XML_IO_WRITE, NULL);
3403 out->error = XML_IO_WRITE;
3404 return(ret);
3405 }
3406 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003407 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3408 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003409 }
3410 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003411 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003412
3413done:
3414#ifdef DEBUG_INPUT
3415 xmlGenericError(xmlGenericErrorContext,
3416 "I/O: wrote %d chars\n", written);
3417#endif
3418 return(written);
3419}
3420
3421/**
Owen Taylor3473f882001-02-23 17:55:21 +00003422 * xmlOutputBufferWriteString:
3423 * @out: a buffered parser output
3424 * @str: a zero terminated C string
3425 *
3426 * Write the content of the string in the output I/O buffer
3427 * This routine handle the I18N transcoding from internal UTF-8
3428 * The buffer is lossless, i.e. will store in case of partial
3429 * or delayed writes.
3430 *
3431 * Returns the number of chars immediately written, or -1
3432 * in case of error.
3433 */
3434int
3435xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3436 int len;
3437
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003438 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003439 if (str == NULL)
3440 return(-1);
3441 len = strlen(str);
3442
3443 if (len > 0)
3444 return(xmlOutputBufferWrite(out, len, str));
3445 return(len);
3446}
3447
3448/**
3449 * xmlOutputBufferFlush:
3450 * @out: a buffered output
3451 *
3452 * flushes the output I/O channel
3453 *
3454 * Returns the number of byte written or -1 in case of error.
3455 */
3456int
3457xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3458 int nbchars = 0, ret = 0;
3459
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003460 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003461 /*
3462 * first handle encoding stuff.
3463 */
3464 if ((out->conv != NULL) && (out->encoder != NULL)) {
3465 /*
3466 * convert as much as possible to the parser reading buffer.
3467 */
3468 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3469 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003470 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003471 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003472 return(-1);
3473 }
3474 }
3475
3476 /*
3477 * second flush the stuff to the I/O channel
3478 */
3479 if ((out->conv != NULL) && (out->encoder != NULL) &&
3480 (out->writecallback != NULL)) {
3481 ret = out->writecallback(out->context,
3482 (const char *)out->conv->content, out->conv->use);
3483 if (ret >= 0)
3484 xmlBufferShrink(out->conv, ret);
3485 } else if (out->writecallback != NULL) {
3486 ret = out->writecallback(out->context,
3487 (const char *)out->buffer->content, out->buffer->use);
3488 if (ret >= 0)
3489 xmlBufferShrink(out->buffer, ret);
3490 }
3491 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003492 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003493 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003494 return(ret);
3495 }
3496 out->written += ret;
3497
3498#ifdef DEBUG_INPUT
3499 xmlGenericError(xmlGenericErrorContext,
3500 "I/O: flushed %d chars\n", ret);
3501#endif
3502 return(ret);
3503}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003504#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003505
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003506/**
Owen Taylor3473f882001-02-23 17:55:21 +00003507 * xmlParserGetDirectory:
3508 * @filename: the path to a file
3509 *
3510 * lookup the directory for that file
3511 *
3512 * Returns a new allocated string containing the directory, or NULL.
3513 */
3514char *
3515xmlParserGetDirectory(const char *filename) {
3516 char *ret = NULL;
3517 char dir[1024];
3518 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003519
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003520#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3521 return NULL;
3522#endif
3523
Owen Taylor3473f882001-02-23 17:55:21 +00003524 if (xmlInputCallbackInitialized == 0)
3525 xmlRegisterDefaultInputCallbacks();
3526
3527 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003528
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003529#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003530# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3531#else
3532# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003533#endif
3534
3535 strncpy(dir, filename, 1023);
3536 dir[1023] = 0;
3537 cur = &dir[strlen(dir)];
3538 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003539 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003540 cur --;
3541 }
Rob Richardsf779da32007-08-14 09:41:21 +00003542 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003543 if (cur == dir) dir[1] = 0;
3544 else *cur = 0;
3545 ret = xmlMemStrdup(dir);
3546 } else {
3547 if (getcwd(dir, 1024) != NULL) {
3548 dir[1023] = 0;
3549 ret = xmlMemStrdup(dir);
3550 }
3551 }
3552 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003553#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003554}
3555
3556/****************************************************************
3557 * *
3558 * External entities loading *
3559 * *
3560 ****************************************************************/
3561
Daniel Veillarda840b692003-10-19 13:35:37 +00003562/**
3563 * xmlCheckHTTPInput:
3564 * @ctxt: an XML parser context
3565 * @ret: an XML parser input
3566 *
3567 * Check an input in case it was created from an HTTP stream, in that
3568 * case it will handle encoding and update of the base URL in case of
3569 * redirection. It also checks for HTTP errors in which case the input
3570 * is cleanly freed up and an appropriate error is raised in context
3571 *
3572 * Returns the input or NULL in case of HTTP error.
3573 */
3574xmlParserInputPtr
3575xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3576#ifdef LIBXML_HTTP_ENABLED
3577 if ((ret != NULL) && (ret->buf != NULL) &&
3578 (ret->buf->readcallback == xmlIOHTTPRead) &&
3579 (ret->buf->context != NULL)) {
3580 const char *encoding;
3581 const char *redir;
3582 const char *mime;
3583 int code;
3584
3585 code = xmlNanoHTTPReturnCode(ret->buf->context);
3586 if (code >= 400) {
3587 /* fatal error */
3588 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003589 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003590 (const char *) ret->filename);
3591 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003592 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003593 xmlFreeInputStream(ret);
3594 ret = NULL;
3595 } else {
3596
3597 mime = xmlNanoHTTPMimeType(ret->buf->context);
3598 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3599 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3600 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3601 if (encoding != NULL) {
3602 xmlCharEncodingHandlerPtr handler;
3603
3604 handler = xmlFindCharEncodingHandler(encoding);
3605 if (handler != NULL) {
3606 xmlSwitchInputEncoding(ctxt, ret, handler);
3607 } else {
3608 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3609 "Unknown encoding %s",
3610 BAD_CAST encoding, NULL);
3611 }
3612 if (ret->encoding == NULL)
3613 ret->encoding = xmlStrdup(BAD_CAST encoding);
3614 }
3615#if 0
3616 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3617#endif
3618 }
3619 redir = xmlNanoHTTPRedir(ret->buf->context);
3620 if (redir != NULL) {
3621 if (ret->filename != NULL)
3622 xmlFree((xmlChar *) ret->filename);
3623 if (ret->directory != NULL) {
3624 xmlFree((xmlChar *) ret->directory);
3625 ret->directory = NULL;
3626 }
3627 ret->filename =
3628 (char *) xmlStrdup((const xmlChar *) redir);
3629 }
3630 }
3631 }
3632#endif
3633 return(ret);
3634}
3635
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003636static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003637 const char *path;
3638
3639 if (URL == NULL)
3640 return(0);
3641
Daniel Veillardf4862f02002-09-10 11:13:43 +00003642 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003643#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003644 path = &URL[17];
3645#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003646 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003647#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003648 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003649#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003650 path = &URL[8];
3651#else
3652 path = &URL[7];
3653#endif
3654 } else
3655 path = URL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003656
3657 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003658}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003659
Daniel Veillardad4e2962006-09-21 08:36:38 +00003660#ifdef LIBXML_CATALOG_ENABLED
3661
3662/**
3663 * xmlResolveResourceFromCatalog:
3664 * @URL: the URL for the entity to load
3665 * @ID: the System ID for the entity to load
3666 * @ctxt: the context in which the entity is called or NULL
3667 *
3668 * Resolves the URL and ID against the appropriate catalog.
3669 * This function is used by xmlDefaultExternalEntityLoader and
3670 * xmlNoNetExternalEntityLoader.
3671 *
3672 * Returns a new allocated URL, or NULL.
3673 */
William M. Brack38d452a2007-05-22 16:00:06 +00003674static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003675xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3676 xmlParserCtxtPtr ctxt) {
3677 xmlChar *resource = NULL;
3678 xmlCatalogAllow pref;
3679
3680 /*
3681 * If the resource doesn't exists as a file,
3682 * try to load it from the resource pointed in the catalogs
3683 */
3684 pref = xmlCatalogGetDefaults();
3685
3686 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3687 /*
3688 * Do a local lookup
3689 */
3690 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3691 ((pref == XML_CATA_ALLOW_ALL) ||
3692 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3693 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3694 (const xmlChar *)ID,
3695 (const xmlChar *)URL);
3696 }
3697 /*
3698 * Try a global lookup
3699 */
3700 if ((resource == NULL) &&
3701 ((pref == XML_CATA_ALLOW_ALL) ||
3702 (pref == XML_CATA_ALLOW_GLOBAL))) {
3703 resource = xmlCatalogResolve((const xmlChar *)ID,
3704 (const xmlChar *)URL);
3705 }
3706 if ((resource == NULL) && (URL != NULL))
3707 resource = xmlStrdup((const xmlChar *) URL);
3708
3709 /*
3710 * TODO: do an URI lookup on the reference
3711 */
3712 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3713 xmlChar *tmp = NULL;
3714
3715 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3716 ((pref == XML_CATA_ALLOW_ALL) ||
3717 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3718 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3719 }
3720 if ((tmp == NULL) &&
3721 ((pref == XML_CATA_ALLOW_ALL) ||
3722 (pref == XML_CATA_ALLOW_GLOBAL))) {
3723 tmp = xmlCatalogResolveURI(resource);
3724 }
3725
3726 if (tmp != NULL) {
3727 xmlFree(resource);
3728 resource = tmp;
3729 }
3730 }
3731 }
3732
3733 return resource;
3734}
3735
3736#endif
3737
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003738/**
Owen Taylor3473f882001-02-23 17:55:21 +00003739 * xmlDefaultExternalEntityLoader:
3740 * @URL: the URL for the entity to load
3741 * @ID: the System ID for the entity to load
3742 * @ctxt: the context in which the entity is called or NULL
3743 *
3744 * By default we don't load external entitites, yet.
3745 *
3746 * Returns a new allocated xmlParserInputPtr, or NULL.
3747 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003748static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003749xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003750 xmlParserCtxtPtr ctxt)
3751{
Owen Taylor3473f882001-02-23 17:55:21 +00003752 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003753 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003754
Owen Taylor3473f882001-02-23 17:55:21 +00003755#ifdef DEBUG_EXTERNAL_ENTITIES
3756 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003757 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003758#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00003759 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3760 int options = ctxt->options;
3761
3762 ctxt->options -= XML_PARSE_NONET;
3763 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3764 ctxt->options = options;
3765 return(ret);
3766 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003767#ifdef LIBXML_CATALOG_ENABLED
3768 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003769#endif
3770
3771 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003772 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003773
3774 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003775 if (ID == NULL)
3776 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003777 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003778 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003779 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003780 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003781 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003782 xmlFree(resource);
3783 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003784}
3785
3786static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3787 xmlDefaultExternalEntityLoader;
3788
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003789/**
Owen Taylor3473f882001-02-23 17:55:21 +00003790 * xmlSetExternalEntityLoader:
3791 * @f: the new entity resolver function
3792 *
3793 * Changes the defaultexternal entity resolver function for the application
3794 */
3795void
3796xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3797 xmlCurrentExternalEntityLoader = f;
3798}
3799
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003800/**
Owen Taylor3473f882001-02-23 17:55:21 +00003801 * xmlGetExternalEntityLoader:
3802 *
3803 * Get the default external entity resolver function for the application
3804 *
3805 * Returns the xmlExternalEntityLoader function pointer
3806 */
3807xmlExternalEntityLoader
3808xmlGetExternalEntityLoader(void) {
3809 return(xmlCurrentExternalEntityLoader);
3810}
3811
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003812/**
Owen Taylor3473f882001-02-23 17:55:21 +00003813 * xmlLoadExternalEntity:
3814 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003815 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003816 * @ctxt: the context in which the entity is called or NULL
3817 *
3818 * Load an external entity, note that the use of this function for
3819 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003820 *
3821 * Returns the xmlParserInputPtr or NULL
3822 */
3823xmlParserInputPtr
3824xmlLoadExternalEntity(const char *URL, const char *ID,
3825 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003826 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003827 char *canonicFilename;
3828 xmlParserInputPtr ret;
3829
3830 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3831 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003832 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003833 return(NULL);
3834 }
3835
3836 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3837 xmlFree(canonicFilename);
3838 return(ret);
3839 }
Owen Taylor3473f882001-02-23 17:55:21 +00003840 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3841}
3842
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003843/************************************************************************
3844 * *
3845 * Disabling Network access *
3846 * *
3847 ************************************************************************/
3848
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003849/**
3850 * xmlNoNetExternalEntityLoader:
3851 * @URL: the URL for the entity to load
3852 * @ID: the System ID for the entity to load
3853 * @ctxt: the context in which the entity is called or NULL
3854 *
3855 * A specific entity loader disabling network accesses, though still
3856 * allowing local catalog accesses for resolution.
3857 *
3858 * Returns a new allocated xmlParserInputPtr, or NULL.
3859 */
3860xmlParserInputPtr
3861xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3862 xmlParserCtxtPtr ctxt) {
3863 xmlParserInputPtr input = NULL;
3864 xmlChar *resource = NULL;
3865
3866#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00003867 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003868#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00003869
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003870 if (resource == NULL)
3871 resource = (xmlChar *) URL;
3872
3873 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003874 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3875 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003876 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003877 if (resource != (xmlChar *) URL)
3878 xmlFree(resource);
3879 return(NULL);
3880 }
3881 }
3882 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3883 if (resource != (xmlChar *) URL)
3884 xmlFree(resource);
3885 return(input);
3886}
3887
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003888#define bottom_xmlIO
3889#include "elfgcchack.h"