blob: dd4f7e7d37ef05f7118898bf551079406fae5772 [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 }
2277 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2278 ret->encoder = encoder;
2279 if (encoder != NULL) {
2280 ret->conv = xmlBufferCreateSize(4000);
2281 /*
2282 * This call is designed to initiate the encoder state
2283 */
2284 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2285 } else
2286 ret->conv = NULL;
2287 ret->writecallback = NULL;
2288 ret->closecallback = NULL;
2289 ret->context = NULL;
2290 ret->written = 0;
2291
2292 return(ret);
2293}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002294#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002295
2296/**
2297 * xmlFreeParserInputBuffer:
2298 * @in: a buffered parser input
2299 *
2300 * Free up the memory used by a buffered parser input
2301 */
2302void
2303xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002304 if (in == NULL) return;
2305
Owen Taylor3473f882001-02-23 17:55:21 +00002306 if (in->raw) {
2307 xmlBufferFree(in->raw);
2308 in->raw = NULL;
2309 }
2310 if (in->encoder != NULL) {
2311 xmlCharEncCloseFunc(in->encoder);
2312 }
2313 if (in->closecallback != NULL) {
2314 in->closecallback(in->context);
2315 }
2316 if (in->buffer != NULL) {
2317 xmlBufferFree(in->buffer);
2318 in->buffer = NULL;
2319 }
2320
Owen Taylor3473f882001-02-23 17:55:21 +00002321 xmlFree(in);
2322}
2323
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002324#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002325/**
2326 * xmlOutputBufferClose:
2327 * @out: a buffered output
2328 *
2329 * flushes and close the output I/O channel
2330 * and free up all the associated resources
2331 *
2332 * Returns the number of byte written or -1 in case of error.
2333 */
2334int
Daniel Veillard828ce832003-10-08 19:19:10 +00002335xmlOutputBufferClose(xmlOutputBufferPtr out)
2336{
Owen Taylor3473f882001-02-23 17:55:21 +00002337 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002338 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002339
2340 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002341 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002342 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002343 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002344 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002345 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002346 }
2347 written = out->written;
2348 if (out->conv) {
2349 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002350 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002351 }
2352 if (out->encoder != NULL) {
2353 xmlCharEncCloseFunc(out->encoder);
2354 }
2355 if (out->buffer != NULL) {
2356 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002357 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002358 }
2359
Daniel Veillard828ce832003-10-08 19:19:10 +00002360 if (out->error)
2361 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002362 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002363 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002364}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002365#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002366
Daniel Veillard1b243b42004-06-08 10:16:42 +00002367xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002368__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002369 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002370 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002371 void *context = NULL;
2372
2373 if (xmlInputCallbackInitialized == 0)
2374 xmlRegisterDefaultInputCallbacks();
2375
2376 if (URI == NULL) return(NULL);
2377
2378 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002379 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002380 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002381 */
2382 if (context == NULL) {
2383 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2384 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2385 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002386 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002387 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002388 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002389 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002390 }
Owen Taylor3473f882001-02-23 17:55:21 +00002391 }
2392 }
2393 if (context == NULL) {
2394 return(NULL);
2395 }
2396
2397 /*
2398 * Allocate the Input buffer front-end.
2399 */
2400 ret = xmlAllocParserInputBuffer(enc);
2401 if (ret != NULL) {
2402 ret->context = context;
2403 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2404 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002405#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002406 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2407 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002408 if (((z_stream *)context)->avail_in > 4) {
2409 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002410 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002411 if (gzread(context, buff4, 4) == 4) {
2412 if (strncmp(buff4, cptr, 4) == 0)
2413 ret->compressed = 0;
2414 else
2415 ret->compressed = 1;
2416 gzrewind(context);
2417 }
2418 }
2419 }
2420#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002421 }
William M. Brack42331a92004-07-29 07:07:16 +00002422 else
2423 xmlInputCallbackTable[i].closecallback (context);
2424
Owen Taylor3473f882001-02-23 17:55:21 +00002425 return(ret);
2426}
2427
2428/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002429 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002430 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002431 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002432 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002433 * Create a buffered parser input for the progressive parsing of a file
2434 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002435 * Automatic support for ZLIB/Compress compressed document is provided
2436 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002437 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002438 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002439 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002440 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002441xmlParserInputBufferPtr
2442xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2443 if ((xmlParserInputBufferCreateFilenameValue)) {
2444 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2445 }
2446 return __xmlParserInputBufferCreateFilename(URI, enc);
2447}
2448
2449#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002450xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002451__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002452 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002453 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002454 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002455 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002456 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002457 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002458 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002459#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002460 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002461#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002462
Owen Taylor3473f882001-02-23 17:55:21 +00002463 if (xmlOutputCallbackInitialized == 0)
2464 xmlRegisterDefaultOutputCallbacks();
2465
2466 if (URI == NULL) return(NULL);
2467
Daniel Veillard966a31e2004-05-09 02:58:44 +00002468 puri = xmlParseURI(URI);
2469 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002470#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002471 if ((puri->scheme != NULL) &&
2472 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002473 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002474#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002475 /*
2476 * try to limit the damages of the URI unescaping code.
2477 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002478 if ((puri->scheme == NULL) ||
2479 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002480 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2481 xmlFreeURI(puri);
2482 }
Owen Taylor3473f882001-02-23 17:55:21 +00002483
2484 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002485 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002486 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002487 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002488 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002489 if (unescaped != NULL) {
2490#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002491 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002492 context = xmlGzfileOpenW(unescaped, compression);
2493 if (context != NULL) {
2494 ret = xmlAllocOutputBuffer(encoder);
2495 if (ret != NULL) {
2496 ret->context = context;
2497 ret->writecallback = xmlGzfileWrite;
2498 ret->closecallback = xmlGzfileClose;
2499 }
2500 xmlFree(unescaped);
2501 return(ret);
2502 }
2503 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002504#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002505 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2506 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2507 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2508#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2509 /* Need to pass compression parameter into HTTP open calls */
2510 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2511 context = xmlIOHTTPOpenW(unescaped, compression);
2512 else
2513#endif
2514 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2515 if (context != NULL)
2516 break;
2517 }
2518 }
2519 xmlFree(unescaped);
2520 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002521
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002522 /*
2523 * If this failed try with a non-escaped URI this may be a strange
2524 * filename
2525 */
2526 if (context == NULL) {
2527#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002528 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002529 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002530 if (context != NULL) {
2531 ret = xmlAllocOutputBuffer(encoder);
2532 if (ret != NULL) {
2533 ret->context = context;
2534 ret->writecallback = xmlGzfileWrite;
2535 ret->closecallback = xmlGzfileClose;
2536 }
2537 return(ret);
2538 }
2539 }
2540#endif
2541 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2542 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002543 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002544#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2545 /* Need to pass compression parameter into HTTP open calls */
2546 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2547 context = xmlIOHTTPOpenW(URI, compression);
2548 else
2549#endif
2550 context = xmlOutputCallbackTable[i].opencallback(URI);
2551 if (context != NULL)
2552 break;
2553 }
Owen Taylor3473f882001-02-23 17:55:21 +00002554 }
2555 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002556
Owen Taylor3473f882001-02-23 17:55:21 +00002557 if (context == NULL) {
2558 return(NULL);
2559 }
2560
2561 /*
2562 * Allocate the Output buffer front-end.
2563 */
2564 ret = xmlAllocOutputBuffer(encoder);
2565 if (ret != NULL) {
2566 ret->context = context;
2567 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2568 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2569 }
2570 return(ret);
2571}
Daniel Veillard0335a842004-06-02 16:18:40 +00002572
2573/**
2574 * xmlOutputBufferCreateFilename:
2575 * @URI: a C string containing the URI or filename
2576 * @encoder: the encoding converter or NULL
2577 * @compression: the compression ration (0 none, 9 max).
2578 *
2579 * Create a buffered output for the progressive saving of a file
2580 * If filename is "-' then we use stdout as the output.
2581 * Automatic support for ZLIB/Compress compressed document is provided
2582 * by default if found at compile-time.
2583 * TODO: currently if compression is set, the library only support
2584 * writing to a local file.
2585 *
2586 * Returns the new output or NULL
2587 */
2588xmlOutputBufferPtr
2589xmlOutputBufferCreateFilename(const char *URI,
2590 xmlCharEncodingHandlerPtr encoder,
2591 int compression ATTRIBUTE_UNUSED) {
2592 if ((xmlOutputBufferCreateFilenameValue)) {
2593 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2594 }
2595 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2596}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002597#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002598
2599/**
2600 * xmlParserInputBufferCreateFile:
2601 * @file: a FILE*
2602 * @enc: the charset encoding if known
2603 *
2604 * Create a buffered parser input for the progressive parsing of a FILE *
2605 * buffered C I/O
2606 *
2607 * Returns the new parser input or NULL
2608 */
2609xmlParserInputBufferPtr
2610xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2611 xmlParserInputBufferPtr ret;
2612
2613 if (xmlInputCallbackInitialized == 0)
2614 xmlRegisterDefaultInputCallbacks();
2615
2616 if (file == NULL) return(NULL);
2617
2618 ret = xmlAllocParserInputBuffer(enc);
2619 if (ret != NULL) {
2620 ret->context = file;
2621 ret->readcallback = xmlFileRead;
2622 ret->closecallback = xmlFileFlush;
2623 }
2624
2625 return(ret);
2626}
2627
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002628#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002629/**
2630 * xmlOutputBufferCreateFile:
2631 * @file: a FILE*
2632 * @encoder: the encoding converter or NULL
2633 *
2634 * Create a buffered output for the progressive saving to a FILE *
2635 * buffered C I/O
2636 *
2637 * Returns the new parser output or NULL
2638 */
2639xmlOutputBufferPtr
2640xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2641 xmlOutputBufferPtr ret;
2642
2643 if (xmlOutputCallbackInitialized == 0)
2644 xmlRegisterDefaultOutputCallbacks();
2645
2646 if (file == NULL) return(NULL);
2647
2648 ret = xmlAllocOutputBuffer(encoder);
2649 if (ret != NULL) {
2650 ret->context = file;
2651 ret->writecallback = xmlFileWrite;
2652 ret->closecallback = xmlFileFlush;
2653 }
2654
2655 return(ret);
2656}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002657
2658/**
2659 * xmlOutputBufferCreateBuffer:
2660 * @buffer: a xmlBufferPtr
2661 * @encoder: the encoding converter or NULL
2662 *
2663 * Create a buffered output for the progressive saving to a xmlBuffer
2664 *
2665 * Returns the new parser output or NULL
2666 */
2667xmlOutputBufferPtr
2668xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2669 xmlCharEncodingHandlerPtr encoder) {
2670 xmlOutputBufferPtr ret;
2671
2672 if (buffer == NULL) return(NULL);
2673
Rob Richardsa44f2342005-11-09 18:03:45 +00002674 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2675 xmlBufferWrite,
2676 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002677 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002678
2679 return(ret);
2680}
2681
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002682#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002683
2684/**
2685 * xmlParserInputBufferCreateFd:
2686 * @fd: a file descriptor number
2687 * @enc: the charset encoding if known
2688 *
2689 * Create a buffered parser input for the progressive parsing for the input
2690 * from a file descriptor
2691 *
2692 * Returns the new parser input or NULL
2693 */
2694xmlParserInputBufferPtr
2695xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2696 xmlParserInputBufferPtr ret;
2697
2698 if (fd < 0) return(NULL);
2699
2700 ret = xmlAllocParserInputBuffer(enc);
2701 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002702 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002703 ret->readcallback = xmlFdRead;
2704 ret->closecallback = xmlFdClose;
2705 }
2706
2707 return(ret);
2708}
2709
2710/**
2711 * xmlParserInputBufferCreateMem:
2712 * @mem: the memory input
2713 * @size: the length of the memory block
2714 * @enc: the charset encoding if known
2715 *
2716 * Create a buffered parser input for the progressive parsing for the input
2717 * from a memory area.
2718 *
2719 * Returns the new parser input or NULL
2720 */
2721xmlParserInputBufferPtr
2722xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2723 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002724 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002725
2726 if (size <= 0) return(NULL);
2727 if (mem == NULL) return(NULL);
2728
2729 ret = xmlAllocParserInputBuffer(enc);
2730 if (ret != NULL) {
2731 ret->context = (void *) mem;
2732 ret->readcallback = (xmlInputReadCallback) xmlNop;
2733 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002734 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2735 if (errcode != 0) {
2736 xmlFree(ret);
2737 return(NULL);
2738 }
Owen Taylor3473f882001-02-23 17:55:21 +00002739 }
2740
2741 return(ret);
2742}
2743
2744/**
Daniel Veillard53350552003-09-18 13:35:51 +00002745 * xmlParserInputBufferCreateStatic:
2746 * @mem: the memory input
2747 * @size: the length of the memory block
2748 * @enc: the charset encoding if known
2749 *
2750 * Create a buffered parser input for the progressive parsing for the input
2751 * from an immutable memory area. This will not copy the memory area to
2752 * the buffer, but the memory is expected to be available until the end of
2753 * the parsing, this is useful for example when using mmap'ed file.
2754 *
2755 * Returns the new parser input or NULL
2756 */
2757xmlParserInputBufferPtr
2758xmlParserInputBufferCreateStatic(const char *mem, int size,
2759 xmlCharEncoding enc) {
2760 xmlParserInputBufferPtr ret;
2761
2762 if (size <= 0) return(NULL);
2763 if (mem == NULL) return(NULL);
2764
2765 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2766 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002767 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002768 return(NULL);
2769 }
2770 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002771 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002772 if (ret->buffer == NULL) {
2773 xmlFree(ret);
2774 return(NULL);
2775 }
2776 ret->encoder = xmlGetCharEncodingHandler(enc);
2777 if (ret->encoder != NULL)
2778 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2779 else
2780 ret->raw = NULL;
2781 ret->compressed = -1;
2782 ret->context = (void *) mem;
2783 ret->readcallback = NULL;
2784 ret->closecallback = NULL;
2785
2786 return(ret);
2787}
2788
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002789#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002790/**
Owen Taylor3473f882001-02-23 17:55:21 +00002791 * xmlOutputBufferCreateFd:
2792 * @fd: a file descriptor number
2793 * @encoder: the encoding converter or NULL
2794 *
2795 * Create a buffered output for the progressive saving
2796 * to a file descriptor
2797 *
2798 * Returns the new parser output or NULL
2799 */
2800xmlOutputBufferPtr
2801xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2802 xmlOutputBufferPtr ret;
2803
2804 if (fd < 0) return(NULL);
2805
2806 ret = xmlAllocOutputBuffer(encoder);
2807 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002808 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002809 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002810 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002811 }
2812
2813 return(ret);
2814}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002815#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002816
2817/**
2818 * xmlParserInputBufferCreateIO:
2819 * @ioread: an I/O read function
2820 * @ioclose: an I/O close function
2821 * @ioctx: an I/O handler
2822 * @enc: the charset encoding if known
2823 *
2824 * Create a buffered parser input for the progressive parsing for the input
2825 * from an I/O handler
2826 *
2827 * Returns the new parser input or NULL
2828 */
2829xmlParserInputBufferPtr
2830xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2831 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2832 xmlParserInputBufferPtr ret;
2833
2834 if (ioread == NULL) return(NULL);
2835
2836 ret = xmlAllocParserInputBuffer(enc);
2837 if (ret != NULL) {
2838 ret->context = (void *) ioctx;
2839 ret->readcallback = ioread;
2840 ret->closecallback = ioclose;
2841 }
2842
2843 return(ret);
2844}
2845
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002846#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002847/**
2848 * xmlOutputBufferCreateIO:
2849 * @iowrite: an I/O write function
2850 * @ioclose: an I/O close function
2851 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002852 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002853 *
2854 * Create a buffered output for the progressive saving
2855 * to an I/O handler
2856 *
2857 * Returns the new parser output or NULL
2858 */
2859xmlOutputBufferPtr
2860xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2861 xmlOutputCloseCallback ioclose, void *ioctx,
2862 xmlCharEncodingHandlerPtr encoder) {
2863 xmlOutputBufferPtr ret;
2864
2865 if (iowrite == NULL) return(NULL);
2866
2867 ret = xmlAllocOutputBuffer(encoder);
2868 if (ret != NULL) {
2869 ret->context = (void *) ioctx;
2870 ret->writecallback = iowrite;
2871 ret->closecallback = ioclose;
2872 }
2873
2874 return(ret);
2875}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002876#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002877
2878/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002879 * xmlParserInputBufferCreateFilenameDefault:
2880 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2881 *
2882 * Registers a callback for URI input file handling
2883 *
2884 * Returns the old value of the registration function
2885 */
2886xmlParserInputBufferCreateFilenameFunc
2887xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2888{
2889 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2890 if (old == NULL) {
2891 old = __xmlParserInputBufferCreateFilename;
2892 }
2893
2894 xmlParserInputBufferCreateFilenameValue = func;
2895 return(old);
2896}
2897
2898/**
2899 * xmlOutputBufferCreateFilenameDefault:
2900 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2901 *
2902 * Registers a callback for URI output file handling
2903 *
2904 * Returns the old value of the registration function
2905 */
2906xmlOutputBufferCreateFilenameFunc
2907xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2908{
2909 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2910#ifdef LIBXML_OUTPUT_ENABLED
2911 if (old == NULL) {
2912 old = __xmlOutputBufferCreateFilename;
2913 }
2914#endif
2915 xmlOutputBufferCreateFilenameValue = func;
2916 return(old);
2917}
2918
2919/**
Owen Taylor3473f882001-02-23 17:55:21 +00002920 * xmlParserInputBufferPush:
2921 * @in: a buffered parser input
2922 * @len: the size in bytes of the array.
2923 * @buf: an char array
2924 *
2925 * Push the content of the arry in the input buffer
2926 * This routine handle the I18N transcoding to internal UTF-8
2927 * This is used when operating the parser in progressive (push) mode.
2928 *
2929 * Returns the number of chars read and stored in the buffer, or -1
2930 * in case of error.
2931 */
2932int
2933xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2934 int len, const char *buf) {
2935 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002936 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002937
2938 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002939 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002940 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002941 unsigned int use;
2942
Owen Taylor3473f882001-02-23 17:55:21 +00002943 /*
2944 * Store the data in the incoming raw buffer
2945 */
2946 if (in->raw == NULL) {
2947 in->raw = xmlBufferCreate();
2948 }
William M. Bracka3215c72004-07-31 16:24:01 +00002949 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2950 if (ret != 0)
2951 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002952
2953 /*
2954 * convert as much as possible to the parser reading buffer.
2955 */
Daniel Veillard36711902004-02-11 13:25:26 +00002956 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002957 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2958 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002959 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002960 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002961 return(-1);
2962 }
Daniel Veillard36711902004-02-11 13:25:26 +00002963 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002964 } else {
2965 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002966 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2967 if (ret != 0)
2968 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002969 }
2970#ifdef DEBUG_INPUT
2971 xmlGenericError(xmlGenericErrorContext,
2972 "I/O: pushed %d chars, buffer %d/%d\n",
2973 nbchars, in->buffer->use, in->buffer->size);
2974#endif
2975 return(nbchars);
2976}
2977
2978/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002979 * endOfInput:
2980 *
2981 * When reading from an Input channel indicated end of file or error
2982 * don't reread from it again.
2983 */
2984static int
2985endOfInput (void * context ATTRIBUTE_UNUSED,
2986 char * buffer ATTRIBUTE_UNUSED,
2987 int len ATTRIBUTE_UNUSED) {
2988 return(0);
2989}
2990
2991/**
Owen Taylor3473f882001-02-23 17:55:21 +00002992 * xmlParserInputBufferGrow:
2993 * @in: a buffered parser input
2994 * @len: indicative value of the amount of chars to read
2995 *
2996 * Grow up the content of the input buffer, the old data are preserved
2997 * This routine handle the I18N transcoding to internal UTF-8
2998 * This routine is used when operating the parser in normal (pull) mode
2999 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003000 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003001 * onto in->buffer or in->raw
3002 *
3003 * Returns the number of chars read and stored in the buffer, or -1
3004 * in case of error.
3005 */
3006int
3007xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3008 char *buffer = NULL;
3009 int res = 0;
3010 int nbchars = 0;
3011 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00003012 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00003013
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003014 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003015 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003016 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003017
Owen Taylor3473f882001-02-23 17:55:21 +00003018 buffree = in->buffer->size - in->buffer->use;
3019 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003020 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003021 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003022 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003023 }
Owen Taylor3473f882001-02-23 17:55:21 +00003024
Daniel Veillarde5354492002-05-16 08:43:22 +00003025 needSize = in->buffer->use + len + 1;
3026 if (needSize > in->buffer->size){
3027 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003028 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003029 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003030 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003031 }
Owen Taylor3473f882001-02-23 17:55:21 +00003032 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003033 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003034
3035 /*
3036 * Call the read method for this I/O type.
3037 */
3038 if (in->readcallback != NULL) {
3039 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003040 if (res <= 0)
3041 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003042 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003043 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003044 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003045 return(-1);
3046 }
3047 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003048 return(-1);
3049 }
3050 len = res;
3051 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003052 unsigned int use;
3053
Owen Taylor3473f882001-02-23 17:55:21 +00003054 /*
3055 * Store the data in the incoming raw buffer
3056 */
3057 if (in->raw == NULL) {
3058 in->raw = xmlBufferCreate();
3059 }
William M. Bracka3215c72004-07-31 16:24:01 +00003060 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3061 if (res != 0)
3062 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003063
3064 /*
3065 * convert as much as possible to the parser reading buffer.
3066 */
Daniel Veillard36711902004-02-11 13:25:26 +00003067 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003068 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3069 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003070 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003071 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003072 return(-1);
3073 }
Daniel Veillard36711902004-02-11 13:25:26 +00003074 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003075 } else {
3076 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00003077 in->buffer->use += nbchars;
3078 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003079 }
3080#ifdef DEBUG_INPUT
3081 xmlGenericError(xmlGenericErrorContext,
3082 "I/O: read %d chars, buffer %d/%d\n",
3083 nbchars, in->buffer->use, in->buffer->size);
3084#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003085 return(nbchars);
3086}
3087
3088/**
3089 * xmlParserInputBufferRead:
3090 * @in: a buffered parser input
3091 * @len: indicative value of the amount of chars to read
3092 *
3093 * Refresh the content of the input buffer, the old data are considered
3094 * consumed
3095 * This routine handle the I18N transcoding to internal UTF-8
3096 *
3097 * Returns the number of chars read and stored in the buffer, or -1
3098 * in case of error.
3099 */
3100int
3101xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003102 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003103 if (in->readcallback != NULL)
3104 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003105 else if ((in->buffer != NULL) &&
3106 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3107 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003108 else
3109 return(-1);
3110}
3111
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003112#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003113/**
3114 * xmlOutputBufferWrite:
3115 * @out: a buffered parser output
3116 * @len: the size in bytes of the array.
3117 * @buf: an char array
3118 *
3119 * Write the content of the array in the output I/O buffer
3120 * This routine handle the I18N transcoding from internal UTF-8
3121 * The buffer is lossless, i.e. will store in case of partial
3122 * or delayed writes.
3123 *
3124 * Returns the number of chars immediately written, or -1
3125 * in case of error.
3126 */
3127int
3128xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3129 int nbchars = 0; /* number of chars to output to I/O */
3130 int ret; /* return from function call */
3131 int written = 0; /* number of char written to I/O so far */
3132 int chunk; /* number of byte curreent processed from buf */
3133
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003134 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003135 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003136 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003137
3138 do {
3139 chunk = len;
3140 if (chunk > 4 * MINLEN)
3141 chunk = 4 * MINLEN;
3142
3143 /*
3144 * first handle encoding stuff.
3145 */
3146 if (out->encoder != NULL) {
3147 /*
3148 * Store the data in the incoming raw buffer
3149 */
3150 if (out->conv == NULL) {
3151 out->conv = xmlBufferCreate();
3152 }
William M. Bracka3215c72004-07-31 16:24:01 +00003153 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3154 if (ret != 0)
3155 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003156
3157 if ((out->buffer->use < MINLEN) && (chunk == len))
3158 goto done;
3159
3160 /*
3161 * convert as much as possible to the parser reading buffer.
3162 */
3163 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003164 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003165 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003166 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003167 return(-1);
3168 }
3169 nbchars = out->conv->use;
3170 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003171 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3172 if (ret != 0)
3173 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003174 nbchars = out->buffer->use;
3175 }
3176 buf += chunk;
3177 len -= chunk;
3178
3179 if ((nbchars < MINLEN) && (len <= 0))
3180 goto done;
3181
3182 if (out->writecallback) {
3183 /*
3184 * second write the stuff to the I/O channel
3185 */
3186 if (out->encoder != NULL) {
3187 ret = out->writecallback(out->context,
3188 (const char *)out->conv->content, nbchars);
3189 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003190 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003191 } else {
3192 ret = out->writecallback(out->context,
3193 (const char *)out->buffer->content, nbchars);
3194 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003195 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003196 }
3197 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003198 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003199 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003200 return(ret);
3201 }
3202 out->written += ret;
3203 }
3204 written += nbchars;
3205 } while (len > 0);
3206
3207done:
3208#ifdef DEBUG_INPUT
3209 xmlGenericError(xmlGenericErrorContext,
3210 "I/O: wrote %d chars\n", written);
3211#endif
3212 return(written);
3213}
3214
3215/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003216 * xmlEscapeContent:
3217 * @out: a pointer to an array of bytes to store the result
3218 * @outlen: the length of @out
3219 * @in: a pointer to an array of unescaped UTF-8 bytes
3220 * @inlen: the length of @in
3221 *
3222 * Take a block of UTF-8 chars in and escape them.
3223 * Returns 0 if success, or -1 otherwise
3224 * The value of @inlen after return is the number of octets consumed
3225 * if the return value is positive, else unpredictable.
3226 * The value of @outlen after return is the number of octets consumed.
3227 */
3228static int
3229xmlEscapeContent(unsigned char* out, int *outlen,
3230 const xmlChar* in, int *inlen) {
3231 unsigned char* outstart = out;
3232 const unsigned char* base = in;
3233 unsigned char* outend = out + *outlen;
3234 const unsigned char* inend;
3235
3236 inend = in + (*inlen);
3237
3238 while ((in < inend) && (out < outend)) {
3239 if (*in == '<') {
3240 if (outend - out < 4) break;
3241 *out++ = '&';
3242 *out++ = 'l';
3243 *out++ = 't';
3244 *out++ = ';';
3245 } else if (*in == '>') {
3246 if (outend - out < 4) break;
3247 *out++ = '&';
3248 *out++ = 'g';
3249 *out++ = 't';
3250 *out++ = ';';
3251 } else if (*in == '&') {
3252 if (outend - out < 5) break;
3253 *out++ = '&';
3254 *out++ = 'a';
3255 *out++ = 'm';
3256 *out++ = 'p';
3257 *out++ = ';';
3258 } else if (*in == '\r') {
3259 if (outend - out < 5) break;
3260 *out++ = '&';
3261 *out++ = '#';
3262 *out++ = '1';
3263 *out++ = '3';
3264 *out++ = ';';
3265 } else {
3266 *out++ = (unsigned char) *in;
3267 }
3268 ++in;
3269 }
3270 *outlen = out - outstart;
3271 *inlen = in - base;
3272 return(0);
3273}
3274
3275/**
3276 * xmlOutputBufferWriteEscape:
3277 * @out: a buffered parser output
3278 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003279 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003280 *
3281 * Write the content of the string in the output I/O buffer
3282 * This routine escapes the caracters and then handle the I18N
3283 * transcoding from internal UTF-8
3284 * The buffer is lossless, i.e. will store in case of partial
3285 * or delayed writes.
3286 *
3287 * Returns the number of chars immediately written, or -1
3288 * in case of error.
3289 */
3290int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003291xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3292 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003293 int nbchars = 0; /* number of chars to output to I/O */
3294 int ret; /* return from function call */
3295 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003296 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003297 int chunk; /* number of byte currently processed from str */
3298 int len; /* number of bytes in str */
3299 int cons; /* byte from str consumed */
3300
Daniel Veillardce244ad2004-11-05 10:03:46 +00003301 if ((out == NULL) || (out->error) || (str == NULL) ||
3302 (out->buffer == NULL) ||
3303 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003304 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003305 if (len < 0) return(0);
3306 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003307 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003308
3309 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003310 oldwritten = written;
3311
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003312 /*
3313 * how many bytes to consume and how many bytes to store.
3314 */
3315 cons = len;
3316 chunk = (out->buffer->size - out->buffer->use) - 1;
3317
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003318 /*
3319 * make sure we have enough room to save first, if this is
3320 * not the case force a flush, but make sure we stay in the loop
3321 */
3322 if (chunk < 40) {
3323 nbchars = 0;
3324 oldwritten = -1;
3325 goto flush;
3326 }
3327
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003328 /*
3329 * first handle encoding stuff.
3330 */
3331 if (out->encoder != NULL) {
3332 /*
3333 * Store the data in the incoming raw buffer
3334 */
3335 if (out->conv == NULL) {
3336 out->conv = xmlBufferCreate();
3337 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003338 ret = escaping(out->buffer->content + out->buffer->use ,
3339 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003340 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003341 return(-1);
3342 out->buffer->use += chunk;
3343 out->buffer->content[out->buffer->use] = 0;
3344
3345 if ((out->buffer->use < MINLEN) && (cons == len))
3346 goto done;
3347
3348 /*
3349 * convert as much as possible to the output buffer.
3350 */
3351 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3352 if ((ret < 0) && (ret != -3)) {
3353 xmlIOErr(XML_IO_ENCODER, NULL);
3354 out->error = XML_IO_ENCODER;
3355 return(-1);
3356 }
3357 nbchars = out->conv->use;
3358 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003359 ret = escaping(out->buffer->content + out->buffer->use ,
3360 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003361 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003362 return(-1);
3363 out->buffer->use += chunk;
3364 out->buffer->content[out->buffer->use] = 0;
3365 nbchars = out->buffer->use;
3366 }
3367 str += cons;
3368 len -= cons;
3369
3370 if ((nbchars < MINLEN) && (len <= 0))
3371 goto done;
3372
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003373flush:
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003374 if (out->writecallback) {
3375 /*
3376 * second write the stuff to the I/O channel
3377 */
3378 if (out->encoder != NULL) {
3379 ret = out->writecallback(out->context,
3380 (const char *)out->conv->content, nbchars);
3381 if (ret >= 0)
3382 xmlBufferShrink(out->conv, ret);
3383 } else {
3384 ret = out->writecallback(out->context,
3385 (const char *)out->buffer->content, nbchars);
3386 if (ret >= 0)
3387 xmlBufferShrink(out->buffer, ret);
3388 }
3389 if (ret < 0) {
3390 xmlIOErr(XML_IO_WRITE, NULL);
3391 out->error = XML_IO_WRITE;
3392 return(ret);
3393 }
3394 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003395 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3396 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003397 }
3398 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003399 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003400
3401done:
3402#ifdef DEBUG_INPUT
3403 xmlGenericError(xmlGenericErrorContext,
3404 "I/O: wrote %d chars\n", written);
3405#endif
3406 return(written);
3407}
3408
3409/**
Owen Taylor3473f882001-02-23 17:55:21 +00003410 * xmlOutputBufferWriteString:
3411 * @out: a buffered parser output
3412 * @str: a zero terminated C string
3413 *
3414 * Write the content of the string in the output I/O buffer
3415 * This routine handle the I18N transcoding from internal UTF-8
3416 * The buffer is lossless, i.e. will store in case of partial
3417 * or delayed writes.
3418 *
3419 * Returns the number of chars immediately written, or -1
3420 * in case of error.
3421 */
3422int
3423xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3424 int len;
3425
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003426 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003427 if (str == NULL)
3428 return(-1);
3429 len = strlen(str);
3430
3431 if (len > 0)
3432 return(xmlOutputBufferWrite(out, len, str));
3433 return(len);
3434}
3435
3436/**
3437 * xmlOutputBufferFlush:
3438 * @out: a buffered output
3439 *
3440 * flushes the output I/O channel
3441 *
3442 * Returns the number of byte written or -1 in case of error.
3443 */
3444int
3445xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3446 int nbchars = 0, ret = 0;
3447
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003448 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003449 /*
3450 * first handle encoding stuff.
3451 */
3452 if ((out->conv != NULL) && (out->encoder != NULL)) {
3453 /*
3454 * convert as much as possible to the parser reading buffer.
3455 */
3456 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3457 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003458 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003459 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003460 return(-1);
3461 }
3462 }
3463
3464 /*
3465 * second flush the stuff to the I/O channel
3466 */
3467 if ((out->conv != NULL) && (out->encoder != NULL) &&
3468 (out->writecallback != NULL)) {
3469 ret = out->writecallback(out->context,
3470 (const char *)out->conv->content, out->conv->use);
3471 if (ret >= 0)
3472 xmlBufferShrink(out->conv, ret);
3473 } else if (out->writecallback != NULL) {
3474 ret = out->writecallback(out->context,
3475 (const char *)out->buffer->content, out->buffer->use);
3476 if (ret >= 0)
3477 xmlBufferShrink(out->buffer, ret);
3478 }
3479 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003480 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003481 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003482 return(ret);
3483 }
3484 out->written += ret;
3485
3486#ifdef DEBUG_INPUT
3487 xmlGenericError(xmlGenericErrorContext,
3488 "I/O: flushed %d chars\n", ret);
3489#endif
3490 return(ret);
3491}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003492#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003493
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003494/**
Owen Taylor3473f882001-02-23 17:55:21 +00003495 * xmlParserGetDirectory:
3496 * @filename: the path to a file
3497 *
3498 * lookup the directory for that file
3499 *
3500 * Returns a new allocated string containing the directory, or NULL.
3501 */
3502char *
3503xmlParserGetDirectory(const char *filename) {
3504 char *ret = NULL;
3505 char dir[1024];
3506 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003507
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003508#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3509 return NULL;
3510#endif
3511
Owen Taylor3473f882001-02-23 17:55:21 +00003512 if (xmlInputCallbackInitialized == 0)
3513 xmlRegisterDefaultInputCallbacks();
3514
3515 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003516
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003517#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003518# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3519#else
3520# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003521#endif
3522
3523 strncpy(dir, filename, 1023);
3524 dir[1023] = 0;
3525 cur = &dir[strlen(dir)];
3526 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003527 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003528 cur --;
3529 }
Rob Richardsf779da32007-08-14 09:41:21 +00003530 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003531 if (cur == dir) dir[1] = 0;
3532 else *cur = 0;
3533 ret = xmlMemStrdup(dir);
3534 } else {
3535 if (getcwd(dir, 1024) != NULL) {
3536 dir[1023] = 0;
3537 ret = xmlMemStrdup(dir);
3538 }
3539 }
3540 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003541#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003542}
3543
3544/****************************************************************
3545 * *
3546 * External entities loading *
3547 * *
3548 ****************************************************************/
3549
Daniel Veillarda840b692003-10-19 13:35:37 +00003550/**
3551 * xmlCheckHTTPInput:
3552 * @ctxt: an XML parser context
3553 * @ret: an XML parser input
3554 *
3555 * Check an input in case it was created from an HTTP stream, in that
3556 * case it will handle encoding and update of the base URL in case of
3557 * redirection. It also checks for HTTP errors in which case the input
3558 * is cleanly freed up and an appropriate error is raised in context
3559 *
3560 * Returns the input or NULL in case of HTTP error.
3561 */
3562xmlParserInputPtr
3563xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3564#ifdef LIBXML_HTTP_ENABLED
3565 if ((ret != NULL) && (ret->buf != NULL) &&
3566 (ret->buf->readcallback == xmlIOHTTPRead) &&
3567 (ret->buf->context != NULL)) {
3568 const char *encoding;
3569 const char *redir;
3570 const char *mime;
3571 int code;
3572
3573 code = xmlNanoHTTPReturnCode(ret->buf->context);
3574 if (code >= 400) {
3575 /* fatal error */
3576 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003577 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003578 (const char *) ret->filename);
3579 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003580 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003581 xmlFreeInputStream(ret);
3582 ret = NULL;
3583 } else {
3584
3585 mime = xmlNanoHTTPMimeType(ret->buf->context);
3586 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3587 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3588 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3589 if (encoding != NULL) {
3590 xmlCharEncodingHandlerPtr handler;
3591
3592 handler = xmlFindCharEncodingHandler(encoding);
3593 if (handler != NULL) {
3594 xmlSwitchInputEncoding(ctxt, ret, handler);
3595 } else {
3596 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3597 "Unknown encoding %s",
3598 BAD_CAST encoding, NULL);
3599 }
3600 if (ret->encoding == NULL)
3601 ret->encoding = xmlStrdup(BAD_CAST encoding);
3602 }
3603#if 0
3604 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3605#endif
3606 }
3607 redir = xmlNanoHTTPRedir(ret->buf->context);
3608 if (redir != NULL) {
3609 if (ret->filename != NULL)
3610 xmlFree((xmlChar *) ret->filename);
3611 if (ret->directory != NULL) {
3612 xmlFree((xmlChar *) ret->directory);
3613 ret->directory = NULL;
3614 }
3615 ret->filename =
3616 (char *) xmlStrdup((const xmlChar *) redir);
3617 }
3618 }
3619 }
3620#endif
3621 return(ret);
3622}
3623
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003624static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003625 const char *path;
3626
3627 if (URL == NULL)
3628 return(0);
3629
Daniel Veillardf4862f02002-09-10 11:13:43 +00003630 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003631#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003632 path = &URL[17];
3633#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003634 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003635#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003636 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003637#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003638 path = &URL[8];
3639#else
3640 path = &URL[7];
3641#endif
3642 } else
3643 path = URL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003644
3645 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003646}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003647
Daniel Veillardad4e2962006-09-21 08:36:38 +00003648#ifdef LIBXML_CATALOG_ENABLED
3649
3650/**
3651 * xmlResolveResourceFromCatalog:
3652 * @URL: the URL for the entity to load
3653 * @ID: the System ID for the entity to load
3654 * @ctxt: the context in which the entity is called or NULL
3655 *
3656 * Resolves the URL and ID against the appropriate catalog.
3657 * This function is used by xmlDefaultExternalEntityLoader and
3658 * xmlNoNetExternalEntityLoader.
3659 *
3660 * Returns a new allocated URL, or NULL.
3661 */
William M. Brack38d452a2007-05-22 16:00:06 +00003662static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003663xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3664 xmlParserCtxtPtr ctxt) {
3665 xmlChar *resource = NULL;
3666 xmlCatalogAllow pref;
3667
3668 /*
3669 * If the resource doesn't exists as a file,
3670 * try to load it from the resource pointed in the catalogs
3671 */
3672 pref = xmlCatalogGetDefaults();
3673
3674 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3675 /*
3676 * Do a local lookup
3677 */
3678 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3679 ((pref == XML_CATA_ALLOW_ALL) ||
3680 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3681 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3682 (const xmlChar *)ID,
3683 (const xmlChar *)URL);
3684 }
3685 /*
3686 * Try a global lookup
3687 */
3688 if ((resource == NULL) &&
3689 ((pref == XML_CATA_ALLOW_ALL) ||
3690 (pref == XML_CATA_ALLOW_GLOBAL))) {
3691 resource = xmlCatalogResolve((const xmlChar *)ID,
3692 (const xmlChar *)URL);
3693 }
3694 if ((resource == NULL) && (URL != NULL))
3695 resource = xmlStrdup((const xmlChar *) URL);
3696
3697 /*
3698 * TODO: do an URI lookup on the reference
3699 */
3700 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3701 xmlChar *tmp = NULL;
3702
3703 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3704 ((pref == XML_CATA_ALLOW_ALL) ||
3705 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3706 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3707 }
3708 if ((tmp == NULL) &&
3709 ((pref == XML_CATA_ALLOW_ALL) ||
3710 (pref == XML_CATA_ALLOW_GLOBAL))) {
3711 tmp = xmlCatalogResolveURI(resource);
3712 }
3713
3714 if (tmp != NULL) {
3715 xmlFree(resource);
3716 resource = tmp;
3717 }
3718 }
3719 }
3720
3721 return resource;
3722}
3723
3724#endif
3725
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003726/**
Owen Taylor3473f882001-02-23 17:55:21 +00003727 * xmlDefaultExternalEntityLoader:
3728 * @URL: the URL for the entity to load
3729 * @ID: the System ID for the entity to load
3730 * @ctxt: the context in which the entity is called or NULL
3731 *
3732 * By default we don't load external entitites, yet.
3733 *
3734 * Returns a new allocated xmlParserInputPtr, or NULL.
3735 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003736static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003737xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003738 xmlParserCtxtPtr ctxt)
3739{
Owen Taylor3473f882001-02-23 17:55:21 +00003740 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003741 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003742
Owen Taylor3473f882001-02-23 17:55:21 +00003743#ifdef DEBUG_EXTERNAL_ENTITIES
3744 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003745 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003746#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00003747 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3748 int options = ctxt->options;
3749
3750 ctxt->options -= XML_PARSE_NONET;
3751 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3752 ctxt->options = options;
3753 return(ret);
3754 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003755#ifdef LIBXML_CATALOG_ENABLED
3756 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003757#endif
3758
3759 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003760 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003761
3762 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003763 if (ID == NULL)
3764 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003765 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003766 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003767 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003768 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003769 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003770 xmlFree(resource);
3771 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003772}
3773
3774static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3775 xmlDefaultExternalEntityLoader;
3776
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003777/**
Owen Taylor3473f882001-02-23 17:55:21 +00003778 * xmlSetExternalEntityLoader:
3779 * @f: the new entity resolver function
3780 *
3781 * Changes the defaultexternal entity resolver function for the application
3782 */
3783void
3784xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3785 xmlCurrentExternalEntityLoader = f;
3786}
3787
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003788/**
Owen Taylor3473f882001-02-23 17:55:21 +00003789 * xmlGetExternalEntityLoader:
3790 *
3791 * Get the default external entity resolver function for the application
3792 *
3793 * Returns the xmlExternalEntityLoader function pointer
3794 */
3795xmlExternalEntityLoader
3796xmlGetExternalEntityLoader(void) {
3797 return(xmlCurrentExternalEntityLoader);
3798}
3799
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003800/**
Owen Taylor3473f882001-02-23 17:55:21 +00003801 * xmlLoadExternalEntity:
3802 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003803 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003804 * @ctxt: the context in which the entity is called or NULL
3805 *
3806 * Load an external entity, note that the use of this function for
3807 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003808 *
3809 * Returns the xmlParserInputPtr or NULL
3810 */
3811xmlParserInputPtr
3812xmlLoadExternalEntity(const char *URL, const char *ID,
3813 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003814 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003815 char *canonicFilename;
3816 xmlParserInputPtr ret;
3817
3818 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3819 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003820 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003821 return(NULL);
3822 }
3823
3824 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3825 xmlFree(canonicFilename);
3826 return(ret);
3827 }
Owen Taylor3473f882001-02-23 17:55:21 +00003828 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3829}
3830
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003831/************************************************************************
3832 * *
3833 * Disabling Network access *
3834 * *
3835 ************************************************************************/
3836
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003837/**
3838 * xmlNoNetExternalEntityLoader:
3839 * @URL: the URL for the entity to load
3840 * @ID: the System ID for the entity to load
3841 * @ctxt: the context in which the entity is called or NULL
3842 *
3843 * A specific entity loader disabling network accesses, though still
3844 * allowing local catalog accesses for resolution.
3845 *
3846 * Returns a new allocated xmlParserInputPtr, or NULL.
3847 */
3848xmlParserInputPtr
3849xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3850 xmlParserCtxtPtr ctxt) {
3851 xmlParserInputPtr input = NULL;
3852 xmlChar *resource = NULL;
3853
3854#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00003855 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003856#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00003857
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003858 if (resource == NULL)
3859 resource = (xmlChar *) URL;
3860
3861 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003862 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3863 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003864 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003865 if (resource != (xmlChar *) URL)
3866 xmlFree(resource);
3867 return(NULL);
3868 }
3869 }
3870 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3871 if (resource != (xmlChar *) URL)
3872 xmlFree(resource);
3873 return(input);
3874}
3875
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003876#define bottom_xmlIO
3877#include "elfgcchack.h"