blob: 89692f2e78ff08b3d69ea49cbae2679163bf5521 [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 Veillardf7416012006-04-27 08:15:20 +000039#ifdef WIN32
40#include <windows.h>
41#endif
42
Owen Taylor3473f882001-02-23 17:55:21 +000043/* Figure a portable way to know if a file is a directory. */
44#ifndef HAVE_STAT
45# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000046 /* MS C library seems to define stat and _stat. The definition
47 is identical. Still, mapping them to each other causes a warning. */
48# ifndef _MSC_VER
49# define stat(x,y) _stat(x,y)
50# endif
Owen Taylor3473f882001-02-23 17:55:21 +000051# define HAVE_STAT
52# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000053#else
54# ifdef HAVE__STAT
55# define stat _stat
56# endif
Owen Taylor3473f882001-02-23 17:55:21 +000057#endif
58#ifdef HAVE_STAT
59# ifndef S_ISDIR
60# ifdef _S_ISDIR
61# define S_ISDIR(x) _S_ISDIR(x)
62# else
63# ifdef S_IFDIR
64# ifndef S_IFMT
65# ifdef _S_IFMT
66# define S_IFMT _S_IFMT
67# endif
68# endif
69# ifdef S_IFMT
70# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
71# endif
72# endif
73# endif
74# endif
75#endif
76
77#include <libxml/xmlmemory.h>
78#include <libxml/parser.h>
79#include <libxml/parserInternals.h>
80#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000081#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000082#include <libxml/nanohttp.h>
83#include <libxml/nanoftp.h>
84#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000085#ifdef LIBXML_CATALOG_ENABLED
86#include <libxml/catalog.h>
87#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000088#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000089
Daniel Veillardf012a642001-07-23 19:10:52 +000090/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000091/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000092/* #define DEBUG_INPUT */
93
94#ifdef DEBUG_INPUT
95#define MINLEN 40
96#else
97#define MINLEN 4000
98#endif
99
100/*
101 * Input I/O callback sets
102 */
103typedef struct _xmlInputCallback {
104 xmlInputMatchCallback matchcallback;
105 xmlInputOpenCallback opencallback;
106 xmlInputReadCallback readcallback;
107 xmlInputCloseCallback closecallback;
108} xmlInputCallback;
109
110#define MAX_INPUT_CALLBACK 15
111
Daniel Veillard22090732001-07-16 00:06:07 +0000112static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
113static int xmlInputCallbackNr = 0;
114static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000115
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000116#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000117/*
118 * Output I/O callback sets
119 */
120typedef struct _xmlOutputCallback {
121 xmlOutputMatchCallback matchcallback;
122 xmlOutputOpenCallback opencallback;
123 xmlOutputWriteCallback writecallback;
124 xmlOutputCloseCallback closecallback;
125} xmlOutputCallback;
126
127#define MAX_OUTPUT_CALLBACK 15
128
Daniel Veillard22090732001-07-16 00:06:07 +0000129static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
130static int xmlOutputCallbackNr = 0;
131static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000132#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000133
Daniel Veillard05d987b2003-10-08 11:54:57 +0000134/************************************************************************
135 * *
136 * Tree memory error handler *
137 * *
138 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000139
Daniel Veillard05d987b2003-10-08 11:54:57 +0000140static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000141 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000142 "Permission denied", /* EACCES */
143 "Resource temporarily unavailable",/* EAGAIN */
144 "Bad file descriptor", /* EBADF */
145 "Bad message", /* EBADMSG */
146 "Resource busy", /* EBUSY */
147 "Operation canceled", /* ECANCELED */
148 "No child processes", /* ECHILD */
149 "Resource deadlock avoided",/* EDEADLK */
150 "Domain error", /* EDOM */
151 "File exists", /* EEXIST */
152 "Bad address", /* EFAULT */
153 "File too large", /* EFBIG */
154 "Operation in progress", /* EINPROGRESS */
155 "Interrupted function call",/* EINTR */
156 "Invalid argument", /* EINVAL */
157 "Input/output error", /* EIO */
158 "Is a directory", /* EISDIR */
159 "Too many open files", /* EMFILE */
160 "Too many links", /* EMLINK */
161 "Inappropriate message buffer length",/* EMSGSIZE */
162 "Filename too long", /* ENAMETOOLONG */
163 "Too many open files in system",/* ENFILE */
164 "No such device", /* ENODEV */
165 "No such file or directory",/* ENOENT */
166 "Exec format error", /* ENOEXEC */
167 "No locks available", /* ENOLCK */
168 "Not enough space", /* ENOMEM */
169 "No space left on device", /* ENOSPC */
170 "Function not implemented", /* ENOSYS */
171 "Not a directory", /* ENOTDIR */
172 "Directory not empty", /* ENOTEMPTY */
173 "Not supported", /* ENOTSUP */
174 "Inappropriate I/O control operation",/* ENOTTY */
175 "No such device or address",/* ENXIO */
176 "Operation not permitted", /* EPERM */
177 "Broken pipe", /* EPIPE */
178 "Result too large", /* ERANGE */
179 "Read-only file system", /* EROFS */
180 "Invalid seek", /* ESPIPE */
181 "No such process", /* ESRCH */
182 "Operation timed out", /* ETIMEDOUT */
183 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000184 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000185 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000186 "flush error",
187 "write error",
188 "no input",
189 "buffer full",
190 "loading error",
191 "not a socket", /* ENOTSOCK */
192 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000193 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000194 "unreachable network", /* ENETUNREACH */
195 "adddress in use", /* EADDRINUSE */
196 "already in use", /* EALREADY */
197 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000198};
199
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000200#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000201/**
202 * __xmlIOWin32UTF8ToWChar:
203 * @u8String: uft-8 string
204 *
205 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
206 */
207static wchar_t *
208__xmlIOWin32UTF8ToWChar(const char *u8String)
209{
210 wchar_t *wString = NULL;
211
212 if (u8String)
213 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000214 int wLen = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,u8String,-1,NULL,0);
Daniel Veillardf7416012006-04-27 08:15:20 +0000215 if (wLen)
216 {
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000217 wString = xmlMalloc(wLen * sizeof(wchar_t));
Daniel Veillardf7416012006-04-27 08:15:20 +0000218 if (wString)
219 {
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000220 if (MultiByteToWideChar(CP_UTF8,0,u8String,-1,wString,wLen) == 0)
Daniel Veillardf7416012006-04-27 08:15:20 +0000221 {
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000222 xmlFree(wString);
Daniel Veillardf7416012006-04-27 08:15:20 +0000223 wString = NULL;
224 }
225 }
226 }
227 }
228
229 return wString;
230}
231#endif
232
Daniel Veillard05d987b2003-10-08 11:54:57 +0000233/**
234 * xmlIOErrMemory:
235 * @extra: extra informations
236 *
237 * Handle an out of memory condition
238 */
239static void
240xmlIOErrMemory(const char *extra)
241{
242 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
243}
244
245/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000246 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000247 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000248 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000249 * @extra: extra informations
250 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000251 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000252 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000253void
254__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000255{
256 unsigned int idx;
257
258 if (code == 0) {
259#ifdef HAVE_ERRNO_H
260 if (errno == 0) code = 0;
261#ifdef EACCES
262 else if (errno == EACCES) code = XML_IO_EACCES;
263#endif
264#ifdef EAGAIN
265 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
266#endif
267#ifdef EBADF
268 else if (errno == EBADF) code = XML_IO_EBADF;
269#endif
270#ifdef EBADMSG
271 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
272#endif
273#ifdef EBUSY
274 else if (errno == EBUSY) code = XML_IO_EBUSY;
275#endif
276#ifdef ECANCELED
277 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
278#endif
279#ifdef ECHILD
280 else if (errno == ECHILD) code = XML_IO_ECHILD;
281#endif
282#ifdef EDEADLK
283 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
284#endif
285#ifdef EDOM
286 else if (errno == EDOM) code = XML_IO_EDOM;
287#endif
288#ifdef EEXIST
289 else if (errno == EEXIST) code = XML_IO_EEXIST;
290#endif
291#ifdef EFAULT
292 else if (errno == EFAULT) code = XML_IO_EFAULT;
293#endif
294#ifdef EFBIG
295 else if (errno == EFBIG) code = XML_IO_EFBIG;
296#endif
297#ifdef EINPROGRESS
298 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
299#endif
300#ifdef EINTR
301 else if (errno == EINTR) code = XML_IO_EINTR;
302#endif
303#ifdef EINVAL
304 else if (errno == EINVAL) code = XML_IO_EINVAL;
305#endif
306#ifdef EIO
307 else if (errno == EIO) code = XML_IO_EIO;
308#endif
309#ifdef EISDIR
310 else if (errno == EISDIR) code = XML_IO_EISDIR;
311#endif
312#ifdef EMFILE
313 else if (errno == EMFILE) code = XML_IO_EMFILE;
314#endif
315#ifdef EMLINK
316 else if (errno == EMLINK) code = XML_IO_EMLINK;
317#endif
318#ifdef EMSGSIZE
319 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
320#endif
321#ifdef ENAMETOOLONG
322 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
323#endif
324#ifdef ENFILE
325 else if (errno == ENFILE) code = XML_IO_ENFILE;
326#endif
327#ifdef ENODEV
328 else if (errno == ENODEV) code = XML_IO_ENODEV;
329#endif
330#ifdef ENOENT
331 else if (errno == ENOENT) code = XML_IO_ENOENT;
332#endif
333#ifdef ENOEXEC
334 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
335#endif
336#ifdef ENOLCK
337 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
338#endif
339#ifdef ENOMEM
340 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
341#endif
342#ifdef ENOSPC
343 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
344#endif
345#ifdef ENOSYS
346 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
347#endif
348#ifdef ENOTDIR
349 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
350#endif
351#ifdef ENOTEMPTY
352 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
353#endif
354#ifdef ENOTSUP
355 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
356#endif
357#ifdef ENOTTY
358 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
359#endif
360#ifdef ENXIO
361 else if (errno == ENXIO) code = XML_IO_ENXIO;
362#endif
363#ifdef EPERM
364 else if (errno == EPERM) code = XML_IO_EPERM;
365#endif
366#ifdef EPIPE
367 else if (errno == EPIPE) code = XML_IO_EPIPE;
368#endif
369#ifdef ERANGE
370 else if (errno == ERANGE) code = XML_IO_ERANGE;
371#endif
372#ifdef EROFS
373 else if (errno == EROFS) code = XML_IO_EROFS;
374#endif
375#ifdef ESPIPE
376 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
377#endif
378#ifdef ESRCH
379 else if (errno == ESRCH) code = XML_IO_ESRCH;
380#endif
381#ifdef ETIMEDOUT
382 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
383#endif
384#ifdef EXDEV
385 else if (errno == EXDEV) code = XML_IO_EXDEV;
386#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000387#ifdef ENOTSOCK
388 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
389#endif
390#ifdef EISCONN
391 else if (errno == EISCONN) code = XML_IO_EISCONN;
392#endif
393#ifdef ECONNREFUSED
394 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
395#endif
396#ifdef ETIMEDOUT
397 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
398#endif
399#ifdef ENETUNREACH
400 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
401#endif
402#ifdef EADDRINUSE
403 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
404#endif
405#ifdef EINPROGRESS
406 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
407#endif
408#ifdef EALREADY
409 else if (errno == EALREADY) code = XML_IO_EALREADY;
410#endif
411#ifdef EAFNOSUPPORT
412 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
413#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000414 else code = XML_IO_UNKNOWN;
415#endif /* HAVE_ERRNO_H */
416 }
417 idx = 0;
418 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
419 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
420
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000421 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
422}
423
424/**
425 * xmlIOErr:
426 * @code: the error number
427 * @extra: extra informations
428 *
429 * Handle an I/O error
430 */
431static void
432xmlIOErr(int code, const char *extra)
433{
434 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000435}
436
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000437/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000438 * __xmlLoaderErr:
439 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000440 * @extra: extra informations
441 *
442 * Handle a resource access error
443 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000444void
445__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000446{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000447 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000448 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000449 xmlGenericErrorFunc channel = NULL;
450 void *data = NULL;
451 xmlErrorLevel level = XML_ERR_ERROR;
452
Daniel Veillard157fee02003-10-31 10:36:03 +0000453 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
454 (ctxt->instate == XML_PARSER_EOF))
455 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000456 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
457 if (ctxt->validate) {
458 channel = ctxt->sax->error;
459 level = XML_ERR_ERROR;
460 } else {
461 channel = ctxt->sax->warning;
462 level = XML_ERR_WARNING;
463 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000464 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
465 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000466 data = ctxt->userData;
467 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000468 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000469 XML_IO_LOAD_ERROR, level, NULL, 0,
470 filename, NULL, NULL, 0, 0,
471 msg, filename);
472
473}
474
Daniel Veillard05d987b2003-10-08 11:54:57 +0000475/************************************************************************
476 * *
477 * Tree memory error handler *
478 * *
479 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000480/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000481 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000482 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000483 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000484 * This function is obsolete. Please see xmlURIFromPath in uri.c for
485 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000486 *
487 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000488 */
489xmlChar *
490xmlNormalizeWindowsPath(const xmlChar *path)
491{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000492 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000493}
494
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000495/**
496 * xmlCleanupInputCallbacks:
497 *
498 * clears the entire input callback table. this includes the
499 * compiled-in I/O.
500 */
501void
502xmlCleanupInputCallbacks(void)
503{
504 int i;
505
506 if (!xmlInputCallbackInitialized)
507 return;
508
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000509 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000510 xmlInputCallbackTable[i].matchcallback = NULL;
511 xmlInputCallbackTable[i].opencallback = NULL;
512 xmlInputCallbackTable[i].readcallback = NULL;
513 xmlInputCallbackTable[i].closecallback = NULL;
514 }
515
516 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000517 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000518}
519
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000520/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000521 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000522 *
523 * Clear the top input callback from the input stack. this includes the
524 * compiled-in I/O.
525 *
526 * Returns the number of input callback registered or -1 in case of error.
527 */
528int
529xmlPopInputCallbacks(void)
530{
531 if (!xmlInputCallbackInitialized)
532 return(-1);
533
534 if (xmlInputCallbackNr <= 0)
535 return(-1);
536
537 xmlInputCallbackNr--;
538 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
539 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
540 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
541 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
542
543 return(xmlInputCallbackNr);
544}
545
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000546#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000547/**
548 * xmlCleanupOutputCallbacks:
549 *
550 * clears the entire output callback table. this includes the
551 * compiled-in I/O callbacks.
552 */
553void
554xmlCleanupOutputCallbacks(void)
555{
556 int i;
557
558 if (!xmlOutputCallbackInitialized)
559 return;
560
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000561 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000562 xmlOutputCallbackTable[i].matchcallback = NULL;
563 xmlOutputCallbackTable[i].opencallback = NULL;
564 xmlOutputCallbackTable[i].writecallback = NULL;
565 xmlOutputCallbackTable[i].closecallback = NULL;
566 }
567
568 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000569 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000570}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000571#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000572
Owen Taylor3473f882001-02-23 17:55:21 +0000573/************************************************************************
574 * *
575 * Standard I/O for file accesses *
576 * *
577 ************************************************************************/
578
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000579#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
580
581/**
582 * xmlWrapOpenUtf8:
583 * @path: the path in utf-8 encoding
584 * @mode: type of access (0 - read, 1 - write)
585 *
586 * function opens the file specified by @path
587 *
588 */
589static FILE*
590xmlWrapOpenUtf8(const char *path,int mode)
591{
592 FILE *fd = NULL;
593 wchar_t *wPath;
594
595 wPath = __xmlIOWin32UTF8ToWChar(path);
596 if(wPath)
597 {
598 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
599 xmlFree(wPath);
600 }
601 // maybe path in native encoding
602 if(fd == NULL)
603 fd = fopen(path, mode ? "wb" : "rb");
604
605 return fd;
606}
607
608/**
609 * xmlWrapStatUtf8:
610 * @path: the path in utf-8 encoding
611 * @info: structure that stores results
612 *
613 * function obtains information about the file or directory
614 *
615 */
616static int
617xmlWrapStatUtf8(const char *path,struct stat *info)
618{
619#ifdef HAVE_STAT
620 int retval = -1;
621 wchar_t *wPath;
622
623 wPath = __xmlIOWin32UTF8ToWChar(path);
624 if (wPath)
625 {
626 retval = _wstat(wPath,info);
627 xmlFree(wPath);
628 }
629 // maybe path in native encoding
630 if(retval < 0)
631 retval = stat(path,info);
632 return retval;
633#else
634 return -1;
635#endif
636}
637
638/**
639 * xmlWrapOpenNative:
640 * @path: the path
641 * @mode: type of access (0 - read, 1 - write)
642 *
643 * function opens the file specified by @path
644 *
645 */
646static FILE*
647xmlWrapOpenNative(const char *path,int mode)
648{
649 return fopen(path,mode ? "wb" : "rb");
650}
651
652/**
653 * xmlWrapStatNative:
654 * @path: the path
655 * @info: structure that stores results
656 *
657 * function obtains information about the file or directory
658 *
659 */
660static int
661xmlWrapStatNative(const char *path,struct stat *info)
662{
663#ifdef HAVE_STAT
664 return stat(path,info);
665#else
666 return -1;
667#endif
668}
669
670static int (* xmlWrapStat)(const char *,struct stat *) = xmlWrapStatNative;
671static FILE* (* xmlWrapOpen)(const char *,int mode) = xmlWrapOpenNative;
672
673/**
674 * xmlInitPlatformSpecificIo:
675 *
676 * Initialize platform specific features.
677 */
678static void
679xmlInitPlatformSpecificIo
680(void) {
681 static int xmlPlatformIoInitialized = 0;
682 OSVERSIONINFO osvi;
683
684 if(xmlPlatformIoInitialized)
685 return;
686
687 osvi.dwOSVersionInfoSize = sizeof(osvi);
688
689 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
690 xmlWrapStat = xmlWrapStatUtf8;
691 xmlWrapOpen = xmlWrapOpenUtf8;
692 } else {
693 xmlWrapStat = xmlWrapStatNative;
694 xmlWrapOpen = xmlWrapOpenNative;
695 }
696
697 xmlPlatformIoInitialized = 1;
698 return;
699}
700
701#endif
702
Owen Taylor3473f882001-02-23 17:55:21 +0000703/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000704 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000705 * @path: the path to check
706 *
707 * function checks to see if @path is a valid source
708 * (file, socket...) for XML.
709 *
710 * if stat is not available on the target machine,
711 * returns 1. if stat fails, returns 0 (if calling
712 * stat on the filename fails, it can't be right).
713 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000714 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000715 */
716
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000717int
Owen Taylor3473f882001-02-23 17:55:21 +0000718xmlCheckFilename (const char *path)
719{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000720#ifdef HAVE_STAT
Daniel Veillard0b309952006-05-02 20:34:38 +0000721 struct stat stat_buffer;
722#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000723 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000724 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000725
Owen Taylor3473f882001-02-23 17:55:21 +0000726#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000727#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
728 if (xmlWrapStat(path, &stat_buffer) == -1)
729 return 0;
730#else
Owen Taylor3473f882001-02-23 17:55:21 +0000731 if (stat(path, &stat_buffer) == -1)
732 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000733#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000734#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000735 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000736 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000737#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000738#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000739 return 1;
740}
741
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000742static int
Owen Taylor3473f882001-02-23 17:55:21 +0000743xmlNop(void) {
744 return(0);
745}
746
747/**
Owen Taylor3473f882001-02-23 17:55:21 +0000748 * xmlFdRead:
749 * @context: the I/O context
750 * @buffer: where to drop data
751 * @len: number of bytes to read
752 *
753 * Read @len bytes to @buffer from the I/O channel.
754 *
755 * Returns the number of bytes written
756 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000757static int
Owen Taylor3473f882001-02-23 17:55:21 +0000758xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000759 int ret;
760
761 ret = read((int) (long) context, &buffer[0], len);
762 if (ret < 0) xmlIOErr(0, "read()");
763 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000764}
765
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000766#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000767/**
768 * xmlFdWrite:
769 * @context: the I/O context
770 * @buffer: where to get data
771 * @len: number of bytes to write
772 *
773 * Write @len bytes from @buffer to the I/O channel.
774 *
775 * Returns the number of bytes written
776 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000777static int
Owen Taylor3473f882001-02-23 17:55:21 +0000778xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000779 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000780
Daniel Veillard9b693b42005-10-28 14:54:17 +0000781 if (len > 0) {
782 ret = write((int) (long) context, &buffer[0], len);
783 if (ret < 0) xmlIOErr(0, "write()");
784 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000785 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000786}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000787#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000788
789/**
790 * xmlFdClose:
791 * @context: the I/O context
792 *
793 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000794 *
795 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000796 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000797static int
Owen Taylor3473f882001-02-23 17:55:21 +0000798xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000799 int ret;
800 ret = close((int) (long) context);
801 if (ret < 0) xmlIOErr(0, "close()");
802 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000803}
804
805/**
806 * xmlFileMatch:
807 * @filename: the URI for matching
808 *
809 * input from FILE *
810 *
811 * Returns 1 if matches, 0 otherwise
812 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000813int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000814xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000815 return(1);
816}
817
818/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000819 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000820 * @filename: the URI for matching
821 *
822 * input from FILE *, supports compressed input
823 * if @filename is " " then the standard input is used
824 *
825 * Returns an I/O context or NULL in case of error
826 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000827static void *
828xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000829 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000830 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000831
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000832 if (filename == NULL)
833 return(NULL);
834
Owen Taylor3473f882001-02-23 17:55:21 +0000835 if (!strcmp(filename, "-")) {
836 fd = stdin;
837 return((void *) fd);
838 }
839
Daniel Veillardf4862f02002-09-10 11:13:43 +0000840 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000841#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000842 path = &filename[17];
843#else
Owen Taylor3473f882001-02-23 17:55:21 +0000844 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000845#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000846 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000847#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000848 path = &filename[8];
849#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000850 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000851#endif
852 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000853 path = filename;
854
855 if (path == NULL)
856 return(NULL);
857 if (!xmlCheckFilename(path))
858 return(NULL);
859
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000860#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
861 fd = xmlWrapOpen(path, 0);
862#else
863 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000864#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000865 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000866 return((void *) fd);
867}
868
869/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000870 * xmlFileOpen:
871 * @filename: the URI for matching
872 *
873 * Wrapper around xmlFileOpen_real that try it with an unescaped
874 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000875 *
876 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000877 */
878void *
879xmlFileOpen (const char *filename) {
880 char *unescaped;
881 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000882
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000883 unescaped = xmlURIUnescapeString(filename, 0, NULL);
884 if (unescaped != NULL) {
885 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000886 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000887 } else {
888 retval = xmlFileOpen_real(filename);
889 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000890 return retval;
891}
892
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000893#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000894/**
Owen Taylor3473f882001-02-23 17:55:21 +0000895 * xmlFileOpenW:
896 * @filename: the URI for matching
897 *
898 * output to from FILE *,
899 * if @filename is "-" then the standard output is used
900 *
901 * Returns an I/O context or NULL in case of error
902 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000903static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000904xmlFileOpenW (const char *filename) {
905 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000906 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000907
908 if (!strcmp(filename, "-")) {
909 fd = stdout;
910 return((void *) fd);
911 }
912
Daniel Veillardf4862f02002-09-10 11:13:43 +0000913 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000914#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000915 path = &filename[17];
916#else
Owen Taylor3473f882001-02-23 17:55:21 +0000917 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000918#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000919 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000920#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000921 path = &filename[8];
922#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000923 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000924#endif
925 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000926 path = filename;
927
928 if (path == NULL)
929 return(NULL);
930
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000931#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
932 fd = xmlWrapOpen(path, 1);
933#else
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000934 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000935#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000936
Daniel Veillardf7416012006-04-27 08:15:20 +0000937 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000938 return((void *) fd);
939}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000940#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000941
942/**
943 * xmlFileRead:
944 * @context: the I/O context
945 * @buffer: where to drop data
946 * @len: number of bytes to write
947 *
948 * Read @len bytes to @buffer from the I/O channel.
949 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000950 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000951 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000952int
Owen Taylor3473f882001-02-23 17:55:21 +0000953xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000954 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000955 if ((context == NULL) || (buffer == NULL))
956 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000957 ret = fread(&buffer[0], 1, len, (FILE *) context);
958 if (ret < 0) xmlIOErr(0, "fread()");
959 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000960}
961
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000962#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000963/**
964 * xmlFileWrite:
965 * @context: the I/O context
966 * @buffer: where to drop data
967 * @len: number of bytes to write
968 *
969 * Write @len bytes from @buffer to the I/O channel.
970 *
971 * Returns the number of bytes written
972 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000973static int
Owen Taylor3473f882001-02-23 17:55:21 +0000974xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000975 int items;
976
Daniel Veillardce682bc2004-11-05 17:22:25 +0000977 if ((context == NULL) || (buffer == NULL))
978 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000979 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000980 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000981 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000982 return(-1);
983 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000984 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000985}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000986#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000987
988/**
989 * xmlFileClose:
990 * @context: the I/O context
991 *
992 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000993 *
994 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000995 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000996int
Owen Taylor3473f882001-02-23 17:55:21 +0000997xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000998 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000999 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001000
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001001 if (context == NULL)
1002 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001003 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001004 if ((fil == stdout) || (fil == stderr)) {
1005 ret = fflush(fil);
1006 if (ret < 0)
1007 xmlIOErr(0, "fflush()");
1008 return(0);
1009 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001010 if (fil == stdin)
1011 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001012 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1013 if (ret < 0)
1014 xmlIOErr(0, "fclose()");
1015 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001016}
1017
1018/**
1019 * xmlFileFlush:
1020 * @context: the I/O context
1021 *
1022 * Flush an I/O channel
1023 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001024static int
Owen Taylor3473f882001-02-23 17:55:21 +00001025xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001026 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001027
1028 if (context == NULL)
1029 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001030 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1031 if (ret < 0)
1032 xmlIOErr(0, "fflush()");
1033 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001034}
1035
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001036#ifdef LIBXML_OUTPUT_ENABLED
1037/**
1038 * xmlBufferWrite:
1039 * @context: the xmlBuffer
1040 * @buffer: the data to write
1041 * @len: number of bytes to write
1042 *
1043 * Write @len bytes from @buffer to the xml buffer
1044 *
1045 * Returns the number of bytes written
1046 */
1047static int
1048xmlBufferWrite (void * context, const char * buffer, int len) {
1049 int ret;
1050
1051 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1052 if (ret != 0)
1053 return(-1);
1054 return(len);
1055}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001056#endif
1057
Owen Taylor3473f882001-02-23 17:55:21 +00001058#ifdef HAVE_ZLIB_H
1059/************************************************************************
1060 * *
1061 * I/O for compressed file accesses *
1062 * *
1063 ************************************************************************/
1064/**
1065 * xmlGzfileMatch:
1066 * @filename: the URI for matching
1067 *
1068 * input from compressed file test
1069 *
1070 * Returns 1 if matches, 0 otherwise
1071 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001072static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001073xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001074 return(1);
1075}
1076
1077/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001078 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001079 * @filename: the URI for matching
1080 *
1081 * input from compressed file open
1082 * if @filename is " " then the standard input is used
1083 *
1084 * Returns an I/O context or NULL in case of error
1085 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001086static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001087xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001088 const char *path = NULL;
1089 gzFile fd;
1090
1091 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001092 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001093 return((void *) fd);
1094 }
1095
Daniel Veillardf4862f02002-09-10 11:13:43 +00001096 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001097#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001098 path = &filename[17];
1099#else
Owen Taylor3473f882001-02-23 17:55:21 +00001100 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001101#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001102 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001103#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001104 path = &filename[8];
1105#else
Owen Taylor3473f882001-02-23 17:55:21 +00001106 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001107#endif
1108 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001109 path = filename;
1110
1111 if (path == NULL)
1112 return(NULL);
1113 if (!xmlCheckFilename(path))
1114 return(NULL);
1115
1116 fd = gzopen(path, "rb");
1117 return((void *) fd);
1118}
1119
1120/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001121 * xmlGzfileOpen:
1122 * @filename: the URI for matching
1123 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001124 * Wrapper around xmlGzfileOpen if the open fais, it will
1125 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001126 */
1127static void *
1128xmlGzfileOpen (const char *filename) {
1129 char *unescaped;
1130 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001131
1132 retval = xmlGzfileOpen_real(filename);
1133 if (retval == NULL) {
1134 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1135 if (unescaped != NULL) {
1136 retval = xmlGzfileOpen_real(unescaped);
1137 }
1138 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001139 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001140 return retval;
1141}
1142
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001143#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001144/**
Owen Taylor3473f882001-02-23 17:55:21 +00001145 * xmlGzfileOpenW:
1146 * @filename: the URI for matching
1147 * @compression: the compression factor (0 - 9 included)
1148 *
1149 * input from compressed file open
1150 * if @filename is " " then the standard input is used
1151 *
1152 * Returns an I/O context or NULL in case of error
1153 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001154static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001155xmlGzfileOpenW (const char *filename, int compression) {
1156 const char *path = NULL;
1157 char mode[15];
1158 gzFile fd;
1159
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001160 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001161 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001162 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001163 return((void *) fd);
1164 }
1165
Daniel Veillardf4862f02002-09-10 11:13:43 +00001166 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001167#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001168 path = &filename[17];
1169#else
Owen Taylor3473f882001-02-23 17:55:21 +00001170 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001171#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001172 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001173#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001174 path = &filename[8];
1175#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001176 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001177#endif
1178 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001179 path = filename;
1180
1181 if (path == NULL)
1182 return(NULL);
1183
1184 fd = gzopen(path, mode);
1185 return((void *) fd);
1186}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001187#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001188
1189/**
1190 * xmlGzfileRead:
1191 * @context: the I/O context
1192 * @buffer: where to drop data
1193 * @len: number of bytes to write
1194 *
1195 * Read @len bytes to @buffer from the compressed I/O channel.
1196 *
1197 * Returns the number of bytes written
1198 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001199static int
Owen Taylor3473f882001-02-23 17:55:21 +00001200xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001201 int ret;
1202
1203 ret = gzread((gzFile) context, &buffer[0], len);
1204 if (ret < 0) xmlIOErr(0, "gzread()");
1205 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001206}
1207
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001208#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001209/**
1210 * xmlGzfileWrite:
1211 * @context: the I/O context
1212 * @buffer: where to drop data
1213 * @len: number of bytes to write
1214 *
1215 * Write @len bytes from @buffer to the compressed I/O channel.
1216 *
1217 * Returns the number of bytes written
1218 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001219static int
Owen Taylor3473f882001-02-23 17:55:21 +00001220xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001221 int ret;
1222
1223 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1224 if (ret < 0) xmlIOErr(0, "gzwrite()");
1225 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001226}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001227#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001228
1229/**
1230 * xmlGzfileClose:
1231 * @context: the I/O context
1232 *
1233 * Close a compressed I/O channel
1234 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001235static int
Owen Taylor3473f882001-02-23 17:55:21 +00001236xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001237 int ret;
1238
1239 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1240 if (ret < 0) xmlIOErr(0, "gzclose()");
1241 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001242}
1243#endif /* HAVE_ZLIB_H */
1244
1245#ifdef LIBXML_HTTP_ENABLED
1246/************************************************************************
1247 * *
1248 * I/O for HTTP file accesses *
1249 * *
1250 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001251
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001252#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001253typedef struct xmlIOHTTPWriteCtxt_
1254{
1255 int compression;
1256
1257 char * uri;
1258
1259 void * doc_buff;
1260
1261} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1262
1263#ifdef HAVE_ZLIB_H
1264
1265#define DFLT_WBITS ( -15 )
1266#define DFLT_MEM_LVL ( 8 )
1267#define GZ_MAGIC1 ( 0x1f )
1268#define GZ_MAGIC2 ( 0x8b )
1269#define LXML_ZLIB_OS_CODE ( 0x03 )
1270#define INIT_HTTP_BUFF_SIZE ( 32768 )
1271#define DFLT_ZLIB_RATIO ( 5 )
1272
1273/*
1274** Data structure and functions to work with sending compressed data
1275** via HTTP.
1276*/
1277
1278typedef struct xmlZMemBuff_
1279{
1280 unsigned long size;
1281 unsigned long crc;
1282
1283 unsigned char * zbuff;
1284 z_stream zctrl;
1285
1286} xmlZMemBuff, *xmlZMemBuffPtr;
1287
1288/**
1289 * append_reverse_ulong
1290 * @buff: Compressed memory buffer
1291 * @data: Unsigned long to append
1292 *
1293 * Append a unsigned long in reverse byte order to the end of the
1294 * memory buffer.
1295 */
1296static void
1297append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1298
1299 int idx;
1300
1301 if ( buff == NULL )
1302 return;
1303
1304 /*
1305 ** This is plagiarized from putLong in gzio.c (zlib source) where
1306 ** the number "4" is hardcoded. If zlib is ever patched to
1307 ** support 64 bit file sizes, this code would need to be patched
1308 ** as well.
1309 */
1310
1311 for ( idx = 0; idx < 4; idx++ ) {
1312 *buff->zctrl.next_out = ( data & 0xff );
1313 data >>= 8;
1314 buff->zctrl.next_out++;
1315 }
1316
1317 return;
1318}
1319
1320/**
1321 *
1322 * xmlFreeZMemBuff
1323 * @buff: The memory buffer context to clear
1324 *
1325 * Release all the resources associated with the compressed memory buffer.
1326 */
1327static void
1328xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001329
1330#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001331 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001332#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001333
1334 if ( buff == NULL )
1335 return;
1336
1337 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001338#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001339 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001340 if ( z_err != Z_OK )
1341 xmlGenericError( xmlGenericErrorContext,
1342 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1343 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001344#else
1345 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001346#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001347
1348 xmlFree( buff );
1349 return;
1350}
1351
1352/**
1353 * xmlCreateZMemBuff
1354 *@compression: Compression value to use
1355 *
1356 * Create a memory buffer to hold the compressed XML document. The
1357 * compressed document in memory will end up being identical to what
1358 * would be created if gzopen/gzwrite/gzclose were being used to
1359 * write the document to disk. The code for the header/trailer data to
1360 * the compression is plagiarized from the zlib source files.
1361 */
1362static void *
1363xmlCreateZMemBuff( int compression ) {
1364
1365 int z_err;
1366 int hdr_lgth;
1367 xmlZMemBuffPtr buff = NULL;
1368
1369 if ( ( compression < 1 ) || ( compression > 9 ) )
1370 return ( NULL );
1371
1372 /* Create the control and data areas */
1373
1374 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1375 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001376 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001377 return ( NULL );
1378 }
1379
1380 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1381 buff->size = INIT_HTTP_BUFF_SIZE;
1382 buff->zbuff = xmlMalloc( buff->size );
1383 if ( buff->zbuff == NULL ) {
1384 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001385 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001386 return ( NULL );
1387 }
1388
1389 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1390 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1391 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001392 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001393 xmlFreeZMemBuff( buff );
1394 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001395 xmlStrPrintf(msg, 500,
1396 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1397 "Error initializing compression context. ZLIB error:",
1398 z_err );
1399 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001400 return ( NULL );
1401 }
1402
1403 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001404 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001405 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1406 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001407 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1408 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1409 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1410 buff->zctrl.avail_out = buff->size - hdr_lgth;
1411
1412 return ( buff );
1413}
1414
1415/**
1416 * xmlZMemBuffExtend
1417 * @buff: Buffer used to compress and consolidate data.
1418 * @ext_amt: Number of bytes to extend the buffer.
1419 *
1420 * Extend the internal buffer used to store the compressed data by the
1421 * specified amount.
1422 *
1423 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1424 * the original buffer still exists at the original size.
1425 */
1426static int
1427xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1428
1429 int rc = -1;
1430 size_t new_size;
1431 size_t cur_used;
1432
1433 unsigned char * tmp_ptr = NULL;
1434
1435 if ( buff == NULL )
1436 return ( -1 );
1437
1438 else if ( ext_amt == 0 )
1439 return ( 0 );
1440
1441 cur_used = buff->zctrl.next_out - buff->zbuff;
1442 new_size = buff->size + ext_amt;
1443
1444#ifdef DEBUG_HTTP
1445 if ( cur_used > new_size )
1446 xmlGenericError( xmlGenericErrorContext,
1447 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1448 "Buffer overwrite detected during compressed memory",
1449 "buffer extension. Overflowed by",
1450 (cur_used - new_size ) );
1451#endif
1452
1453 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1454 if ( tmp_ptr != NULL ) {
1455 rc = 0;
1456 buff->size = new_size;
1457 buff->zbuff = tmp_ptr;
1458 buff->zctrl.next_out = tmp_ptr + cur_used;
1459 buff->zctrl.avail_out = new_size - cur_used;
1460 }
1461 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001462 xmlChar msg[500];
1463 xmlStrPrintf(msg, 500,
1464 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1465 "Allocation failure extending output buffer to",
1466 new_size );
1467 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001468 }
1469
1470 return ( rc );
1471}
1472
1473/**
1474 * xmlZMemBuffAppend
1475 * @buff: Buffer used to compress and consolidate data
1476 * @src: Uncompressed source content to append to buffer
1477 * @len: Length of source data to append to buffer
1478 *
1479 * Compress and append data to the internal buffer. The data buffer
1480 * will be expanded if needed to store the additional data.
1481 *
1482 * Returns the number of bytes appended to the buffer or -1 on error.
1483 */
1484static int
1485xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1486
1487 int z_err;
1488 size_t min_accept;
1489
1490 if ( ( buff == NULL ) || ( src == NULL ) )
1491 return ( -1 );
1492
1493 buff->zctrl.avail_in = len;
1494 buff->zctrl.next_in = (unsigned char *)src;
1495 while ( buff->zctrl.avail_in > 0 ) {
1496 /*
1497 ** Extend the buffer prior to deflate call if a reasonable amount
1498 ** of output buffer space is not available.
1499 */
1500 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1501 if ( buff->zctrl.avail_out <= min_accept ) {
1502 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1503 return ( -1 );
1504 }
1505
1506 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1507 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001508 xmlChar msg[500];
1509 xmlStrPrintf(msg, 500,
1510 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001511 "Compression error while appending",
1512 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001513 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001514 return ( -1 );
1515 }
1516 }
1517
1518 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1519
1520 return ( len );
1521}
1522
1523/**
1524 * xmlZMemBuffGetContent
1525 * @buff: Compressed memory content buffer
1526 * @data_ref: Pointer reference to point to compressed content
1527 *
1528 * Flushes the compression buffers, appends gzip file trailers and
1529 * returns the compressed content and length of the compressed data.
1530 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1531 *
1532 * Returns the length of the compressed data or -1 on error.
1533 */
1534static int
1535xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1536
1537 int zlgth = -1;
1538 int z_err;
1539
1540 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1541 return ( -1 );
1542
1543 /* Need to loop until compression output buffers are flushed */
1544
1545 do
1546 {
1547 z_err = deflate( &buff->zctrl, Z_FINISH );
1548 if ( z_err == Z_OK ) {
1549 /* In this case Z_OK means more buffer space needed */
1550
1551 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1552 return ( -1 );
1553 }
1554 }
1555 while ( z_err == Z_OK );
1556
1557 /* If the compression state is not Z_STREAM_END, some error occurred */
1558
1559 if ( z_err == Z_STREAM_END ) {
1560
1561 /* Need to append the gzip data trailer */
1562
1563 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1564 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1565 return ( -1 );
1566 }
1567
1568 /*
1569 ** For whatever reason, the CRC and length data are pushed out
1570 ** in reverse byte order. So a memcpy can't be used here.
1571 */
1572
1573 append_reverse_ulong( buff, buff->crc );
1574 append_reverse_ulong( buff, buff->zctrl.total_in );
1575
1576 zlgth = buff->zctrl.next_out - buff->zbuff;
1577 *data_ref = (char *)buff->zbuff;
1578 }
1579
Daniel Veillard05d987b2003-10-08 11:54:57 +00001580 else {
1581 xmlChar msg[500];
1582 xmlStrPrintf(msg, 500,
1583 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1584 "Error flushing zlib buffers. Error code", z_err );
1585 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1586 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001587
1588 return ( zlgth );
1589}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001590#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001591#endif /* HAVE_ZLIB_H */
1592
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001593#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001594/**
1595 * xmlFreeHTTPWriteCtxt
1596 * @ctxt: Context to cleanup
1597 *
1598 * Free allocated memory and reclaim system resources.
1599 *
1600 * No return value.
1601 */
1602static void
1603xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1604{
1605 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001606 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001607
1608 if ( ctxt->doc_buff != NULL ) {
1609
1610#ifdef HAVE_ZLIB_H
1611 if ( ctxt->compression > 0 ) {
1612 xmlFreeZMemBuff( ctxt->doc_buff );
1613 }
1614 else
1615#endif
1616 {
1617 xmlOutputBufferClose( ctxt->doc_buff );
1618 }
1619 }
1620
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001621 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001622 return;
1623}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001624#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001625
1626
Owen Taylor3473f882001-02-23 17:55:21 +00001627/**
1628 * xmlIOHTTPMatch:
1629 * @filename: the URI for matching
1630 *
1631 * check if the URI matches an HTTP one
1632 *
1633 * Returns 1 if matches, 0 otherwise
1634 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001635int
Owen Taylor3473f882001-02-23 17:55:21 +00001636xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001637 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001638 return(1);
1639 return(0);
1640}
1641
1642/**
1643 * xmlIOHTTPOpen:
1644 * @filename: the URI for matching
1645 *
1646 * open an HTTP I/O channel
1647 *
1648 * Returns an I/O context or NULL in case of error
1649 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001650void *
Owen Taylor3473f882001-02-23 17:55:21 +00001651xmlIOHTTPOpen (const char *filename) {
1652 return(xmlNanoHTTPOpen(filename, NULL));
1653}
1654
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001655#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001656/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001657 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001658 * @post_uri: The destination URI for the document
1659 * @compression: The compression desired for the document.
1660 *
1661 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1662 * request. Non-static as is called from the output buffer creation routine.
1663 *
1664 * Returns an I/O context or NULL in case of error.
1665 */
1666
1667void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001668xmlIOHTTPOpenW(const char *post_uri, int compression)
1669{
Daniel Veillardf012a642001-07-23 19:10:52 +00001670
Daniel Veillard572577e2002-01-18 16:23:55 +00001671 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001672
Daniel Veillard572577e2002-01-18 16:23:55 +00001673 if (post_uri == NULL)
1674 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001675
Daniel Veillard572577e2002-01-18 16:23:55 +00001676 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1677 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001678 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001679 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001680 }
1681
Daniel Veillard572577e2002-01-18 16:23:55 +00001682 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001683
Daniel Veillard572577e2002-01-18 16:23:55 +00001684 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1685 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001686 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001687 xmlFreeHTTPWriteCtxt(ctxt);
1688 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001689 }
1690
1691 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001692 * ** Since the document length is required for an HTTP post,
1693 * ** need to put the document into a buffer. A memory buffer
1694 * ** is being used to avoid pushing the data to disk and back.
1695 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001696
1697#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001698 if ((compression > 0) && (compression <= 9)) {
1699
1700 ctxt->compression = compression;
1701 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1702 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001703#endif
1704 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001705 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001706
Daniel Veillard572577e2002-01-18 16:23:55 +00001707 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001708 }
1709
Daniel Veillard572577e2002-01-18 16:23:55 +00001710 if (ctxt->doc_buff == NULL) {
1711 xmlFreeHTTPWriteCtxt(ctxt);
1712 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001713 }
1714
Daniel Veillard572577e2002-01-18 16:23:55 +00001715 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001716}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001717#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001718
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001719#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001720/**
1721 * xmlIOHTTPDfltOpenW
1722 * @post_uri: The destination URI for this document.
1723 *
1724 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1725 * HTTP post command. This function should generally not be used as
1726 * the open callback is short circuited in xmlOutputBufferCreateFile.
1727 *
1728 * Returns a pointer to the new IO context.
1729 */
1730static void *
1731xmlIOHTTPDfltOpenW( const char * post_uri ) {
1732 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1733}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001734#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001735
1736/**
Owen Taylor3473f882001-02-23 17:55:21 +00001737 * xmlIOHTTPRead:
1738 * @context: the I/O context
1739 * @buffer: where to drop data
1740 * @len: number of bytes to write
1741 *
1742 * Read @len bytes to @buffer from the I/O channel.
1743 *
1744 * Returns the number of bytes written
1745 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001746int
Owen Taylor3473f882001-02-23 17:55:21 +00001747xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001748 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001749 return(xmlNanoHTTPRead(context, &buffer[0], len));
1750}
1751
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001752#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001753/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001754 * xmlIOHTTPWrite
1755 * @context: previously opened writing context
1756 * @buffer: data to output to temporary buffer
1757 * @len: bytes to output
1758 *
1759 * Collect data from memory buffer into a temporary file for later
1760 * processing.
1761 *
1762 * Returns number of bytes written.
1763 */
1764
1765static int
1766xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1767
1768 xmlIOHTTPWriteCtxtPtr ctxt = context;
1769
1770 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1771 return ( -1 );
1772
1773 if ( len > 0 ) {
1774
1775 /* Use gzwrite or fwrite as previously setup in the open call */
1776
1777#ifdef HAVE_ZLIB_H
1778 if ( ctxt->compression > 0 )
1779 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1780
1781 else
1782#endif
1783 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1784
1785 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001786 xmlChar msg[500];
1787 xmlStrPrintf(msg, 500,
1788 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001789 "Error appending to internal buffer.",
1790 "Error sending document to URI",
1791 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001792 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001793 }
1794 }
1795
1796 return ( len );
1797}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001798#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001799
1800
1801/**
Owen Taylor3473f882001-02-23 17:55:21 +00001802 * xmlIOHTTPClose:
1803 * @context: the I/O context
1804 *
1805 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001806 *
1807 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001808 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001809int
Owen Taylor3473f882001-02-23 17:55:21 +00001810xmlIOHTTPClose (void * context) {
1811 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001812 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001813}
Daniel Veillardf012a642001-07-23 19:10:52 +00001814
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001815#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001816/**
1817 * xmlIOHTTCloseWrite
1818 * @context: The I/O context
1819 * @http_mthd: The HTTP method to be used when sending the data
1820 *
1821 * Close the transmit HTTP I/O channel and actually send the data.
1822 */
1823static int
1824xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1825
1826 int close_rc = -1;
1827 int http_rtn = 0;
1828 int content_lgth = 0;
1829 xmlIOHTTPWriteCtxtPtr ctxt = context;
1830
1831 char * http_content = NULL;
1832 char * content_encoding = NULL;
1833 char * content_type = (char *) "text/xml";
1834 void * http_ctxt = NULL;
1835
1836 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1837 return ( -1 );
1838
1839 /* Retrieve the content from the appropriate buffer */
1840
1841#ifdef HAVE_ZLIB_H
1842
1843 if ( ctxt->compression > 0 ) {
1844 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1845 content_encoding = (char *) "Content-Encoding: gzip";
1846 }
1847 else
1848#endif
1849 {
1850 /* Pull the data out of the memory output buffer */
1851
1852 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1853 http_content = (char *)dctxt->buffer->content;
1854 content_lgth = dctxt->buffer->use;
1855 }
1856
1857 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001858 xmlChar msg[500];
1859 xmlStrPrintf(msg, 500,
1860 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1861 "Error retrieving content.\nUnable to",
1862 http_mthd, "data to URI", ctxt->uri );
1863 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001864 }
1865
1866 else {
1867
1868 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1869 &content_type, content_encoding,
1870 content_lgth );
1871
1872 if ( http_ctxt != NULL ) {
1873#ifdef DEBUG_HTTP
1874 /* If testing/debugging - dump reply with request content */
1875
1876 FILE * tst_file = NULL;
1877 char buffer[ 4096 ];
1878 char * dump_name = NULL;
1879 int avail;
1880
1881 xmlGenericError( xmlGenericErrorContext,
1882 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1883 http_mthd, ctxt->uri,
1884 xmlNanoHTTPReturnCode( http_ctxt ) );
1885
1886 /*
1887 ** Since either content or reply may be gzipped,
1888 ** dump them to separate files instead of the
1889 ** standard error context.
1890 */
1891
1892 dump_name = tempnam( NULL, "lxml" );
1893 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001894 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001895
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001896 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001897 if ( tst_file != NULL ) {
1898 xmlGenericError( xmlGenericErrorContext,
1899 "Transmitted content saved in file: %s\n", buffer );
1900
1901 fwrite( http_content, sizeof( char ),
1902 content_lgth, tst_file );
1903 fclose( tst_file );
1904 }
1905
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001906 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001907 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001908 if ( tst_file != NULL ) {
1909 xmlGenericError( xmlGenericErrorContext,
1910 "Reply content saved in file: %s\n", buffer );
1911
1912
1913 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1914 buffer, sizeof( buffer ) )) > 0 ) {
1915
1916 fwrite( buffer, sizeof( char ), avail, tst_file );
1917 }
1918
1919 fclose( tst_file );
1920 }
1921
1922 free( dump_name );
1923 }
1924#endif /* DEBUG_HTTP */
1925
1926 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1927 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1928 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001929 else {
1930 xmlChar msg[500];
1931 xmlStrPrintf(msg, 500,
1932 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001933 http_mthd, content_lgth,
1934 "bytes to URI", ctxt->uri,
1935 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001936 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1937 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001938
1939 xmlNanoHTTPClose( http_ctxt );
1940 xmlFree( content_type );
1941 }
1942 }
1943
1944 /* Final cleanups */
1945
1946 xmlFreeHTTPWriteCtxt( ctxt );
1947
1948 return ( close_rc );
1949}
1950
1951/**
1952 * xmlIOHTTPClosePut
1953 *
1954 * @context: The I/O context
1955 *
1956 * Close the transmit HTTP I/O channel and actually send data using a PUT
1957 * HTTP method.
1958 */
1959static int
1960xmlIOHTTPClosePut( void * ctxt ) {
1961 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1962}
1963
1964
1965/**
1966 * xmlIOHTTPClosePost
1967 *
1968 * @context: The I/O context
1969 *
1970 * Close the transmit HTTP I/O channel and actually send data using a POST
1971 * HTTP method.
1972 */
1973static int
1974xmlIOHTTPClosePost( void * ctxt ) {
1975 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1976}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001977#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001978
Owen Taylor3473f882001-02-23 17:55:21 +00001979#endif /* LIBXML_HTTP_ENABLED */
1980
1981#ifdef LIBXML_FTP_ENABLED
1982/************************************************************************
1983 * *
1984 * I/O for FTP file accesses *
1985 * *
1986 ************************************************************************/
1987/**
1988 * xmlIOFTPMatch:
1989 * @filename: the URI for matching
1990 *
1991 * check if the URI matches an FTP one
1992 *
1993 * Returns 1 if matches, 0 otherwise
1994 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001995int
Owen Taylor3473f882001-02-23 17:55:21 +00001996xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001997 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001998 return(1);
1999 return(0);
2000}
2001
2002/**
2003 * xmlIOFTPOpen:
2004 * @filename: the URI for matching
2005 *
2006 * open an FTP I/O channel
2007 *
2008 * Returns an I/O context or NULL in case of error
2009 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002010void *
Owen Taylor3473f882001-02-23 17:55:21 +00002011xmlIOFTPOpen (const char *filename) {
2012 return(xmlNanoFTPOpen(filename));
2013}
2014
2015/**
2016 * xmlIOFTPRead:
2017 * @context: the I/O context
2018 * @buffer: where to drop data
2019 * @len: number of bytes to write
2020 *
2021 * Read @len bytes to @buffer from the I/O channel.
2022 *
2023 * Returns the number of bytes written
2024 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002025int
Owen Taylor3473f882001-02-23 17:55:21 +00002026xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002027 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002028 return(xmlNanoFTPRead(context, &buffer[0], len));
2029}
2030
2031/**
2032 * xmlIOFTPClose:
2033 * @context: the I/O context
2034 *
2035 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002036 *
2037 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002038 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002039int
Owen Taylor3473f882001-02-23 17:55:21 +00002040xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002041 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002042}
2043#endif /* LIBXML_FTP_ENABLED */
2044
2045
2046/**
2047 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002048 * @matchFunc: the xmlInputMatchCallback
2049 * @openFunc: the xmlInputOpenCallback
2050 * @readFunc: the xmlInputReadCallback
2051 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002052 *
2053 * Register a new set of I/O callback for handling parser input.
2054 *
2055 * Returns the registered handler number or -1 in case of error
2056 */
2057int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002058xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2059 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2060 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002061 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2062 return(-1);
2063 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002064 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2065 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2066 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2067 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002068 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002069 return(xmlInputCallbackNr++);
2070}
2071
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002072#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002073/**
2074 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002075 * @matchFunc: the xmlOutputMatchCallback
2076 * @openFunc: the xmlOutputOpenCallback
2077 * @writeFunc: the xmlOutputWriteCallback
2078 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002079 *
2080 * Register a new set of I/O callback for handling output.
2081 *
2082 * Returns the registered handler number or -1 in case of error
2083 */
2084int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002085xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2086 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2087 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002088 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
2089 return(-1);
2090 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002091 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2092 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2093 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2094 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002095 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002096 return(xmlOutputCallbackNr++);
2097}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002098#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002099
2100/**
2101 * xmlRegisterDefaultInputCallbacks:
2102 *
2103 * Registers the default compiled-in I/O handlers.
2104 */
2105void
Owen Taylor3473f882001-02-23 17:55:21 +00002106xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002107(void) {
2108 if (xmlInputCallbackInitialized)
2109 return;
2110
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002111#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2112 xmlInitPlatformSpecificIo();
2113#endif
2114
Owen Taylor3473f882001-02-23 17:55:21 +00002115 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2116 xmlFileRead, xmlFileClose);
2117#ifdef HAVE_ZLIB_H
2118 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2119 xmlGzfileRead, xmlGzfileClose);
2120#endif /* HAVE_ZLIB_H */
2121
2122#ifdef LIBXML_HTTP_ENABLED
2123 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2124 xmlIOHTTPRead, xmlIOHTTPClose);
2125#endif /* LIBXML_HTTP_ENABLED */
2126
2127#ifdef LIBXML_FTP_ENABLED
2128 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2129 xmlIOFTPRead, xmlIOFTPClose);
2130#endif /* LIBXML_FTP_ENABLED */
2131 xmlInputCallbackInitialized = 1;
2132}
2133
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002134#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002135/**
2136 * xmlRegisterDefaultOutputCallbacks:
2137 *
2138 * Registers the default compiled-in I/O handlers.
2139 */
2140void
Owen Taylor3473f882001-02-23 17:55:21 +00002141xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002142(void) {
2143 if (xmlOutputCallbackInitialized)
2144 return;
2145
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002146#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2147 xmlInitPlatformSpecificIo();
2148#endif
2149
Owen Taylor3473f882001-02-23 17:55:21 +00002150 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2151 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002152
2153#ifdef LIBXML_HTTP_ENABLED
2154 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2155 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2156#endif
2157
Owen Taylor3473f882001-02-23 17:55:21 +00002158/*********************************
2159 No way a-priori to distinguish between gzipped files from
2160 uncompressed ones except opening if existing then closing
2161 and saving with same compression ratio ... a pain.
2162
2163#ifdef HAVE_ZLIB_H
2164 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2165 xmlGzfileWrite, xmlGzfileClose);
2166#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002167
2168 Nor FTP PUT ....
2169#ifdef LIBXML_FTP_ENABLED
2170 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2171 xmlIOFTPWrite, xmlIOFTPClose);
2172#endif
2173 **********************************/
2174 xmlOutputCallbackInitialized = 1;
2175}
2176
Daniel Veillardf012a642001-07-23 19:10:52 +00002177#ifdef LIBXML_HTTP_ENABLED
2178/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002179 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002180 *
2181 * By default, libxml submits HTTP output requests using the "PUT" method.
2182 * Calling this method changes the HTTP output method to use the "POST"
2183 * method instead.
2184 *
2185 */
2186void
2187xmlRegisterHTTPPostCallbacks( void ) {
2188
2189 /* Register defaults if not done previously */
2190
2191 if ( xmlOutputCallbackInitialized == 0 )
2192 xmlRegisterDefaultOutputCallbacks( );
2193
2194 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2195 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2196 return;
2197}
2198#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002199#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002200
Owen Taylor3473f882001-02-23 17:55:21 +00002201/**
2202 * xmlAllocParserInputBuffer:
2203 * @enc: the charset encoding if known
2204 *
2205 * Create a buffered parser input for progressive parsing
2206 *
2207 * Returns the new parser input or NULL
2208 */
2209xmlParserInputBufferPtr
2210xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2211 xmlParserInputBufferPtr ret;
2212
2213 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2214 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002215 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002216 return(NULL);
2217 }
2218 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002219 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002220 if (ret->buffer == NULL) {
2221 xmlFree(ret);
2222 return(NULL);
2223 }
2224 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2225 ret->encoder = xmlGetCharEncodingHandler(enc);
2226 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002227 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002228 else
2229 ret->raw = NULL;
2230 ret->readcallback = NULL;
2231 ret->closecallback = NULL;
2232 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002233 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002234 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002235
2236 return(ret);
2237}
2238
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002239#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002240/**
2241 * xmlAllocOutputBuffer:
2242 * @encoder: the encoding converter or NULL
2243 *
2244 * Create a buffered parser output
2245 *
2246 * Returns the new parser output or NULL
2247 */
2248xmlOutputBufferPtr
2249xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2250 xmlOutputBufferPtr ret;
2251
2252 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2253 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002254 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002255 return(NULL);
2256 }
2257 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2258 ret->buffer = xmlBufferCreate();
2259 if (ret->buffer == NULL) {
2260 xmlFree(ret);
2261 return(NULL);
2262 }
2263 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2264 ret->encoder = encoder;
2265 if (encoder != NULL) {
2266 ret->conv = xmlBufferCreateSize(4000);
2267 /*
2268 * This call is designed to initiate the encoder state
2269 */
2270 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2271 } else
2272 ret->conv = NULL;
2273 ret->writecallback = NULL;
2274 ret->closecallback = NULL;
2275 ret->context = NULL;
2276 ret->written = 0;
2277
2278 return(ret);
2279}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002280#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002281
2282/**
2283 * xmlFreeParserInputBuffer:
2284 * @in: a buffered parser input
2285 *
2286 * Free up the memory used by a buffered parser input
2287 */
2288void
2289xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002290 if (in == NULL) return;
2291
Owen Taylor3473f882001-02-23 17:55:21 +00002292 if (in->raw) {
2293 xmlBufferFree(in->raw);
2294 in->raw = NULL;
2295 }
2296 if (in->encoder != NULL) {
2297 xmlCharEncCloseFunc(in->encoder);
2298 }
2299 if (in->closecallback != NULL) {
2300 in->closecallback(in->context);
2301 }
2302 if (in->buffer != NULL) {
2303 xmlBufferFree(in->buffer);
2304 in->buffer = NULL;
2305 }
2306
Owen Taylor3473f882001-02-23 17:55:21 +00002307 xmlFree(in);
2308}
2309
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002310#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002311/**
2312 * xmlOutputBufferClose:
2313 * @out: a buffered output
2314 *
2315 * flushes and close the output I/O channel
2316 * and free up all the associated resources
2317 *
2318 * Returns the number of byte written or -1 in case of error.
2319 */
2320int
Daniel Veillard828ce832003-10-08 19:19:10 +00002321xmlOutputBufferClose(xmlOutputBufferPtr out)
2322{
Owen Taylor3473f882001-02-23 17:55:21 +00002323 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002324 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002325
2326 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002327 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002328 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002329 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002330 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002331 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002332 }
2333 written = out->written;
2334 if (out->conv) {
2335 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002336 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002337 }
2338 if (out->encoder != NULL) {
2339 xmlCharEncCloseFunc(out->encoder);
2340 }
2341 if (out->buffer != NULL) {
2342 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002343 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002344 }
2345
Daniel Veillard828ce832003-10-08 19:19:10 +00002346 if (out->error)
2347 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002348 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002349 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002350}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002351#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002352
Daniel Veillard1b243b42004-06-08 10:16:42 +00002353xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002354__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002355 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002356 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002357 void *context = NULL;
2358
2359 if (xmlInputCallbackInitialized == 0)
2360 xmlRegisterDefaultInputCallbacks();
2361
2362 if (URI == NULL) return(NULL);
2363
2364 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002365 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002366 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002367 */
2368 if (context == NULL) {
2369 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2370 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2371 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002372 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002373 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002374 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002375 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002376 }
Owen Taylor3473f882001-02-23 17:55:21 +00002377 }
2378 }
2379 if (context == NULL) {
2380 return(NULL);
2381 }
2382
2383 /*
2384 * Allocate the Input buffer front-end.
2385 */
2386 ret = xmlAllocParserInputBuffer(enc);
2387 if (ret != NULL) {
2388 ret->context = context;
2389 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2390 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002391#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002392 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2393 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002394 if (((z_stream *)context)->avail_in > 4) {
2395 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002396 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002397 if (gzread(context, buff4, 4) == 4) {
2398 if (strncmp(buff4, cptr, 4) == 0)
2399 ret->compressed = 0;
2400 else
2401 ret->compressed = 1;
2402 gzrewind(context);
2403 }
2404 }
2405 }
2406#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002407 }
William M. Brack42331a92004-07-29 07:07:16 +00002408 else
2409 xmlInputCallbackTable[i].closecallback (context);
2410
Owen Taylor3473f882001-02-23 17:55:21 +00002411 return(ret);
2412}
2413
2414/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002415 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002416 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002417 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002418 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002419 * Create a buffered parser input for the progressive parsing of a file
2420 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002421 * Automatic support for ZLIB/Compress compressed document is provided
2422 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002423 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002424 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002425 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002426 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002427xmlParserInputBufferPtr
2428xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2429 if ((xmlParserInputBufferCreateFilenameValue)) {
2430 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2431 }
2432 return __xmlParserInputBufferCreateFilename(URI, enc);
2433}
2434
2435#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002436xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002437__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002438 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002439 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002440 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002441 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002442 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002443 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002444 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002445#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002446 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002447#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002448
Owen Taylor3473f882001-02-23 17:55:21 +00002449 if (xmlOutputCallbackInitialized == 0)
2450 xmlRegisterDefaultOutputCallbacks();
2451
2452 if (URI == NULL) return(NULL);
2453
Daniel Veillard966a31e2004-05-09 02:58:44 +00002454 puri = xmlParseURI(URI);
2455 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002456#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002457 if ((puri->scheme != NULL) &&
2458 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002459 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002460#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002461 /*
2462 * try to limit the damages of the URI unescaping code.
2463 */
2464 if (puri->scheme != NULL)
2465 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2466 xmlFreeURI(puri);
2467 }
Owen Taylor3473f882001-02-23 17:55:21 +00002468
2469 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002470 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002471 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002472 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002473 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002474 if (unescaped != NULL) {
2475#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002476 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002477 context = xmlGzfileOpenW(unescaped, compression);
2478 if (context != NULL) {
2479 ret = xmlAllocOutputBuffer(encoder);
2480 if (ret != NULL) {
2481 ret->context = context;
2482 ret->writecallback = xmlGzfileWrite;
2483 ret->closecallback = xmlGzfileClose;
2484 }
2485 xmlFree(unescaped);
2486 return(ret);
2487 }
2488 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002489#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002490 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2491 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2492 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2493#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2494 /* Need to pass compression parameter into HTTP open calls */
2495 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2496 context = xmlIOHTTPOpenW(unescaped, compression);
2497 else
2498#endif
2499 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2500 if (context != NULL)
2501 break;
2502 }
2503 }
2504 xmlFree(unescaped);
2505 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002506
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002507 /*
2508 * If this failed try with a non-escaped URI this may be a strange
2509 * filename
2510 */
2511 if (context == NULL) {
2512#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002513 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002514 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002515 if (context != NULL) {
2516 ret = xmlAllocOutputBuffer(encoder);
2517 if (ret != NULL) {
2518 ret->context = context;
2519 ret->writecallback = xmlGzfileWrite;
2520 ret->closecallback = xmlGzfileClose;
2521 }
2522 return(ret);
2523 }
2524 }
2525#endif
2526 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2527 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002528 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002529#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2530 /* Need to pass compression parameter into HTTP open calls */
2531 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2532 context = xmlIOHTTPOpenW(URI, compression);
2533 else
2534#endif
2535 context = xmlOutputCallbackTable[i].opencallback(URI);
2536 if (context != NULL)
2537 break;
2538 }
Owen Taylor3473f882001-02-23 17:55:21 +00002539 }
2540 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002541
Owen Taylor3473f882001-02-23 17:55:21 +00002542 if (context == NULL) {
2543 return(NULL);
2544 }
2545
2546 /*
2547 * Allocate the Output buffer front-end.
2548 */
2549 ret = xmlAllocOutputBuffer(encoder);
2550 if (ret != NULL) {
2551 ret->context = context;
2552 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2553 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2554 }
2555 return(ret);
2556}
Daniel Veillard0335a842004-06-02 16:18:40 +00002557
2558/**
2559 * xmlOutputBufferCreateFilename:
2560 * @URI: a C string containing the URI or filename
2561 * @encoder: the encoding converter or NULL
2562 * @compression: the compression ration (0 none, 9 max).
2563 *
2564 * Create a buffered output for the progressive saving of a file
2565 * If filename is "-' then we use stdout as the output.
2566 * Automatic support for ZLIB/Compress compressed document is provided
2567 * by default if found at compile-time.
2568 * TODO: currently if compression is set, the library only support
2569 * writing to a local file.
2570 *
2571 * Returns the new output or NULL
2572 */
2573xmlOutputBufferPtr
2574xmlOutputBufferCreateFilename(const char *URI,
2575 xmlCharEncodingHandlerPtr encoder,
2576 int compression ATTRIBUTE_UNUSED) {
2577 if ((xmlOutputBufferCreateFilenameValue)) {
2578 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2579 }
2580 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2581}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002582#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002583
2584/**
2585 * xmlParserInputBufferCreateFile:
2586 * @file: a FILE*
2587 * @enc: the charset encoding if known
2588 *
2589 * Create a buffered parser input for the progressive parsing of a FILE *
2590 * buffered C I/O
2591 *
2592 * Returns the new parser input or NULL
2593 */
2594xmlParserInputBufferPtr
2595xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2596 xmlParserInputBufferPtr ret;
2597
2598 if (xmlInputCallbackInitialized == 0)
2599 xmlRegisterDefaultInputCallbacks();
2600
2601 if (file == NULL) return(NULL);
2602
2603 ret = xmlAllocParserInputBuffer(enc);
2604 if (ret != NULL) {
2605 ret->context = file;
2606 ret->readcallback = xmlFileRead;
2607 ret->closecallback = xmlFileFlush;
2608 }
2609
2610 return(ret);
2611}
2612
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002613#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002614/**
2615 * xmlOutputBufferCreateFile:
2616 * @file: a FILE*
2617 * @encoder: the encoding converter or NULL
2618 *
2619 * Create a buffered output for the progressive saving to a FILE *
2620 * buffered C I/O
2621 *
2622 * Returns the new parser output or NULL
2623 */
2624xmlOutputBufferPtr
2625xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2626 xmlOutputBufferPtr ret;
2627
2628 if (xmlOutputCallbackInitialized == 0)
2629 xmlRegisterDefaultOutputCallbacks();
2630
2631 if (file == NULL) return(NULL);
2632
2633 ret = xmlAllocOutputBuffer(encoder);
2634 if (ret != NULL) {
2635 ret->context = file;
2636 ret->writecallback = xmlFileWrite;
2637 ret->closecallback = xmlFileFlush;
2638 }
2639
2640 return(ret);
2641}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002642
2643/**
2644 * xmlOutputBufferCreateBuffer:
2645 * @buffer: a xmlBufferPtr
2646 * @encoder: the encoding converter or NULL
2647 *
2648 * Create a buffered output for the progressive saving to a xmlBuffer
2649 *
2650 * Returns the new parser output or NULL
2651 */
2652xmlOutputBufferPtr
2653xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2654 xmlCharEncodingHandlerPtr encoder) {
2655 xmlOutputBufferPtr ret;
2656
2657 if (buffer == NULL) return(NULL);
2658
Rob Richardsa44f2342005-11-09 18:03:45 +00002659 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2660 xmlBufferWrite,
2661 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002662 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002663
2664 return(ret);
2665}
2666
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002667#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002668
2669/**
2670 * xmlParserInputBufferCreateFd:
2671 * @fd: a file descriptor number
2672 * @enc: the charset encoding if known
2673 *
2674 * Create a buffered parser input for the progressive parsing for the input
2675 * from a file descriptor
2676 *
2677 * Returns the new parser input or NULL
2678 */
2679xmlParserInputBufferPtr
2680xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2681 xmlParserInputBufferPtr ret;
2682
2683 if (fd < 0) return(NULL);
2684
2685 ret = xmlAllocParserInputBuffer(enc);
2686 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002687 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002688 ret->readcallback = xmlFdRead;
2689 ret->closecallback = xmlFdClose;
2690 }
2691
2692 return(ret);
2693}
2694
2695/**
2696 * xmlParserInputBufferCreateMem:
2697 * @mem: the memory input
2698 * @size: the length of the memory block
2699 * @enc: the charset encoding if known
2700 *
2701 * Create a buffered parser input for the progressive parsing for the input
2702 * from a memory area.
2703 *
2704 * Returns the new parser input or NULL
2705 */
2706xmlParserInputBufferPtr
2707xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2708 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002709 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002710
2711 if (size <= 0) return(NULL);
2712 if (mem == NULL) return(NULL);
2713
2714 ret = xmlAllocParserInputBuffer(enc);
2715 if (ret != NULL) {
2716 ret->context = (void *) mem;
2717 ret->readcallback = (xmlInputReadCallback) xmlNop;
2718 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002719 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2720 if (errcode != 0) {
2721 xmlFree(ret);
2722 return(NULL);
2723 }
Owen Taylor3473f882001-02-23 17:55:21 +00002724 }
2725
2726 return(ret);
2727}
2728
2729/**
Daniel Veillard53350552003-09-18 13:35:51 +00002730 * xmlParserInputBufferCreateStatic:
2731 * @mem: the memory input
2732 * @size: the length of the memory block
2733 * @enc: the charset encoding if known
2734 *
2735 * Create a buffered parser input for the progressive parsing for the input
2736 * from an immutable memory area. This will not copy the memory area to
2737 * the buffer, but the memory is expected to be available until the end of
2738 * the parsing, this is useful for example when using mmap'ed file.
2739 *
2740 * Returns the new parser input or NULL
2741 */
2742xmlParserInputBufferPtr
2743xmlParserInputBufferCreateStatic(const char *mem, int size,
2744 xmlCharEncoding enc) {
2745 xmlParserInputBufferPtr ret;
2746
2747 if (size <= 0) return(NULL);
2748 if (mem == NULL) return(NULL);
2749
2750 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2751 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002752 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002753 return(NULL);
2754 }
2755 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002756 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002757 if (ret->buffer == NULL) {
2758 xmlFree(ret);
2759 return(NULL);
2760 }
2761 ret->encoder = xmlGetCharEncodingHandler(enc);
2762 if (ret->encoder != NULL)
2763 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2764 else
2765 ret->raw = NULL;
2766 ret->compressed = -1;
2767 ret->context = (void *) mem;
2768 ret->readcallback = NULL;
2769 ret->closecallback = NULL;
2770
2771 return(ret);
2772}
2773
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002774#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002775/**
Owen Taylor3473f882001-02-23 17:55:21 +00002776 * xmlOutputBufferCreateFd:
2777 * @fd: a file descriptor number
2778 * @encoder: the encoding converter or NULL
2779 *
2780 * Create a buffered output for the progressive saving
2781 * to a file descriptor
2782 *
2783 * Returns the new parser output or NULL
2784 */
2785xmlOutputBufferPtr
2786xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2787 xmlOutputBufferPtr ret;
2788
2789 if (fd < 0) return(NULL);
2790
2791 ret = xmlAllocOutputBuffer(encoder);
2792 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002793 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002794 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002795 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002796 }
2797
2798 return(ret);
2799}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002800#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002801
2802/**
2803 * xmlParserInputBufferCreateIO:
2804 * @ioread: an I/O read function
2805 * @ioclose: an I/O close function
2806 * @ioctx: an I/O handler
2807 * @enc: the charset encoding if known
2808 *
2809 * Create a buffered parser input for the progressive parsing for the input
2810 * from an I/O handler
2811 *
2812 * Returns the new parser input or NULL
2813 */
2814xmlParserInputBufferPtr
2815xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2816 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2817 xmlParserInputBufferPtr ret;
2818
2819 if (ioread == NULL) return(NULL);
2820
2821 ret = xmlAllocParserInputBuffer(enc);
2822 if (ret != NULL) {
2823 ret->context = (void *) ioctx;
2824 ret->readcallback = ioread;
2825 ret->closecallback = ioclose;
2826 }
2827
2828 return(ret);
2829}
2830
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002831#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002832/**
2833 * xmlOutputBufferCreateIO:
2834 * @iowrite: an I/O write function
2835 * @ioclose: an I/O close function
2836 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002837 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002838 *
2839 * Create a buffered output for the progressive saving
2840 * to an I/O handler
2841 *
2842 * Returns the new parser output or NULL
2843 */
2844xmlOutputBufferPtr
2845xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2846 xmlOutputCloseCallback ioclose, void *ioctx,
2847 xmlCharEncodingHandlerPtr encoder) {
2848 xmlOutputBufferPtr ret;
2849
2850 if (iowrite == NULL) return(NULL);
2851
2852 ret = xmlAllocOutputBuffer(encoder);
2853 if (ret != NULL) {
2854 ret->context = (void *) ioctx;
2855 ret->writecallback = iowrite;
2856 ret->closecallback = ioclose;
2857 }
2858
2859 return(ret);
2860}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002861#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002862
2863/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002864 * xmlParserInputBufferCreateFilenameDefault:
2865 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2866 *
2867 * Registers a callback for URI input file handling
2868 *
2869 * Returns the old value of the registration function
2870 */
2871xmlParserInputBufferCreateFilenameFunc
2872xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2873{
2874 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2875 if (old == NULL) {
2876 old = __xmlParserInputBufferCreateFilename;
2877 }
2878
2879 xmlParserInputBufferCreateFilenameValue = func;
2880 return(old);
2881}
2882
2883/**
2884 * xmlOutputBufferCreateFilenameDefault:
2885 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2886 *
2887 * Registers a callback for URI output file handling
2888 *
2889 * Returns the old value of the registration function
2890 */
2891xmlOutputBufferCreateFilenameFunc
2892xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2893{
2894 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2895#ifdef LIBXML_OUTPUT_ENABLED
2896 if (old == NULL) {
2897 old = __xmlOutputBufferCreateFilename;
2898 }
2899#endif
2900 xmlOutputBufferCreateFilenameValue = func;
2901 return(old);
2902}
2903
2904/**
Owen Taylor3473f882001-02-23 17:55:21 +00002905 * xmlParserInputBufferPush:
2906 * @in: a buffered parser input
2907 * @len: the size in bytes of the array.
2908 * @buf: an char array
2909 *
2910 * Push the content of the arry in the input buffer
2911 * This routine handle the I18N transcoding to internal UTF-8
2912 * This is used when operating the parser in progressive (push) mode.
2913 *
2914 * Returns the number of chars read and stored in the buffer, or -1
2915 * in case of error.
2916 */
2917int
2918xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2919 int len, const char *buf) {
2920 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002921 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002922
2923 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002924 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002925 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002926 unsigned int use;
2927
Owen Taylor3473f882001-02-23 17:55:21 +00002928 /*
2929 * Store the data in the incoming raw buffer
2930 */
2931 if (in->raw == NULL) {
2932 in->raw = xmlBufferCreate();
2933 }
William M. Bracka3215c72004-07-31 16:24:01 +00002934 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2935 if (ret != 0)
2936 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002937
2938 /*
2939 * convert as much as possible to the parser reading buffer.
2940 */
Daniel Veillard36711902004-02-11 13:25:26 +00002941 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002942 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2943 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002944 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002945 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002946 return(-1);
2947 }
Daniel Veillard36711902004-02-11 13:25:26 +00002948 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002949 } else {
2950 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002951 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2952 if (ret != 0)
2953 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002954 }
2955#ifdef DEBUG_INPUT
2956 xmlGenericError(xmlGenericErrorContext,
2957 "I/O: pushed %d chars, buffer %d/%d\n",
2958 nbchars, in->buffer->use, in->buffer->size);
2959#endif
2960 return(nbchars);
2961}
2962
2963/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002964 * endOfInput:
2965 *
2966 * When reading from an Input channel indicated end of file or error
2967 * don't reread from it again.
2968 */
2969static int
2970endOfInput (void * context ATTRIBUTE_UNUSED,
2971 char * buffer ATTRIBUTE_UNUSED,
2972 int len ATTRIBUTE_UNUSED) {
2973 return(0);
2974}
2975
2976/**
Owen Taylor3473f882001-02-23 17:55:21 +00002977 * xmlParserInputBufferGrow:
2978 * @in: a buffered parser input
2979 * @len: indicative value of the amount of chars to read
2980 *
2981 * Grow up the content of the input buffer, the old data are preserved
2982 * This routine handle the I18N transcoding to internal UTF-8
2983 * This routine is used when operating the parser in normal (pull) mode
2984 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002985 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002986 * onto in->buffer or in->raw
2987 *
2988 * Returns the number of chars read and stored in the buffer, or -1
2989 * in case of error.
2990 */
2991int
2992xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2993 char *buffer = NULL;
2994 int res = 0;
2995 int nbchars = 0;
2996 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002997 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002998
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002999 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003000 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003001 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003002
Owen Taylor3473f882001-02-23 17:55:21 +00003003 buffree = in->buffer->size - in->buffer->use;
3004 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003005 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003006 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003007 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003008 }
Owen Taylor3473f882001-02-23 17:55:21 +00003009
Daniel Veillarde5354492002-05-16 08:43:22 +00003010 needSize = in->buffer->use + len + 1;
3011 if (needSize > in->buffer->size){
3012 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003013 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003014 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003015 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003016 }
Owen Taylor3473f882001-02-23 17:55:21 +00003017 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003018 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003019
3020 /*
3021 * Call the read method for this I/O type.
3022 */
3023 if (in->readcallback != NULL) {
3024 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003025 if (res <= 0)
3026 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003027 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003028 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003029 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003030 return(-1);
3031 }
3032 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003033 return(-1);
3034 }
3035 len = res;
3036 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003037 unsigned int use;
3038
Owen Taylor3473f882001-02-23 17:55:21 +00003039 /*
3040 * Store the data in the incoming raw buffer
3041 */
3042 if (in->raw == NULL) {
3043 in->raw = xmlBufferCreate();
3044 }
William M. Bracka3215c72004-07-31 16:24:01 +00003045 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3046 if (res != 0)
3047 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003048
3049 /*
3050 * convert as much as possible to the parser reading buffer.
3051 */
Daniel Veillard36711902004-02-11 13:25:26 +00003052 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003053 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3054 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003055 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003056 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003057 return(-1);
3058 }
Daniel Veillard36711902004-02-11 13:25:26 +00003059 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003060 } else {
3061 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00003062 in->buffer->use += nbchars;
3063 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003064 }
3065#ifdef DEBUG_INPUT
3066 xmlGenericError(xmlGenericErrorContext,
3067 "I/O: read %d chars, buffer %d/%d\n",
3068 nbchars, in->buffer->use, in->buffer->size);
3069#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003070 return(nbchars);
3071}
3072
3073/**
3074 * xmlParserInputBufferRead:
3075 * @in: a buffered parser input
3076 * @len: indicative value of the amount of chars to read
3077 *
3078 * Refresh the content of the input buffer, the old data are considered
3079 * consumed
3080 * This routine handle the I18N transcoding to internal UTF-8
3081 *
3082 * Returns the number of chars read and stored in the buffer, or -1
3083 * in case of error.
3084 */
3085int
3086xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003087 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003088 if (in->readcallback != NULL)
3089 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003090 else if ((in->buffer != NULL) &&
3091 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3092 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003093 else
3094 return(-1);
3095}
3096
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003097#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003098/**
3099 * xmlOutputBufferWrite:
3100 * @out: a buffered parser output
3101 * @len: the size in bytes of the array.
3102 * @buf: an char array
3103 *
3104 * Write the content of the array in the output I/O buffer
3105 * This routine handle the I18N transcoding from internal UTF-8
3106 * The buffer is lossless, i.e. will store in case of partial
3107 * or delayed writes.
3108 *
3109 * Returns the number of chars immediately written, or -1
3110 * in case of error.
3111 */
3112int
3113xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3114 int nbchars = 0; /* number of chars to output to I/O */
3115 int ret; /* return from function call */
3116 int written = 0; /* number of char written to I/O so far */
3117 int chunk; /* number of byte curreent processed from buf */
3118
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003119 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003120 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003121 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003122
3123 do {
3124 chunk = len;
3125 if (chunk > 4 * MINLEN)
3126 chunk = 4 * MINLEN;
3127
3128 /*
3129 * first handle encoding stuff.
3130 */
3131 if (out->encoder != NULL) {
3132 /*
3133 * Store the data in the incoming raw buffer
3134 */
3135 if (out->conv == NULL) {
3136 out->conv = xmlBufferCreate();
3137 }
William M. Bracka3215c72004-07-31 16:24:01 +00003138 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3139 if (ret != 0)
3140 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003141
3142 if ((out->buffer->use < MINLEN) && (chunk == len))
3143 goto done;
3144
3145 /*
3146 * convert as much as possible to the parser reading buffer.
3147 */
3148 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003149 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003150 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003151 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003152 return(-1);
3153 }
3154 nbchars = out->conv->use;
3155 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003156 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3157 if (ret != 0)
3158 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003159 nbchars = out->buffer->use;
3160 }
3161 buf += chunk;
3162 len -= chunk;
3163
3164 if ((nbchars < MINLEN) && (len <= 0))
3165 goto done;
3166
3167 if (out->writecallback) {
3168 /*
3169 * second write the stuff to the I/O channel
3170 */
3171 if (out->encoder != NULL) {
3172 ret = out->writecallback(out->context,
3173 (const char *)out->conv->content, nbchars);
3174 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003175 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003176 } else {
3177 ret = out->writecallback(out->context,
3178 (const char *)out->buffer->content, nbchars);
3179 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003180 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003181 }
3182 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003183 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003184 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003185 return(ret);
3186 }
3187 out->written += ret;
3188 }
3189 written += nbchars;
3190 } while (len > 0);
3191
3192done:
3193#ifdef DEBUG_INPUT
3194 xmlGenericError(xmlGenericErrorContext,
3195 "I/O: wrote %d chars\n", written);
3196#endif
3197 return(written);
3198}
3199
3200/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003201 * xmlEscapeContent:
3202 * @out: a pointer to an array of bytes to store the result
3203 * @outlen: the length of @out
3204 * @in: a pointer to an array of unescaped UTF-8 bytes
3205 * @inlen: the length of @in
3206 *
3207 * Take a block of UTF-8 chars in and escape them.
3208 * Returns 0 if success, or -1 otherwise
3209 * The value of @inlen after return is the number of octets consumed
3210 * if the return value is positive, else unpredictable.
3211 * The value of @outlen after return is the number of octets consumed.
3212 */
3213static int
3214xmlEscapeContent(unsigned char* out, int *outlen,
3215 const xmlChar* in, int *inlen) {
3216 unsigned char* outstart = out;
3217 const unsigned char* base = in;
3218 unsigned char* outend = out + *outlen;
3219 const unsigned char* inend;
3220
3221 inend = in + (*inlen);
3222
3223 while ((in < inend) && (out < outend)) {
3224 if (*in == '<') {
3225 if (outend - out < 4) break;
3226 *out++ = '&';
3227 *out++ = 'l';
3228 *out++ = 't';
3229 *out++ = ';';
3230 } else if (*in == '>') {
3231 if (outend - out < 4) break;
3232 *out++ = '&';
3233 *out++ = 'g';
3234 *out++ = 't';
3235 *out++ = ';';
3236 } else if (*in == '&') {
3237 if (outend - out < 5) break;
3238 *out++ = '&';
3239 *out++ = 'a';
3240 *out++ = 'm';
3241 *out++ = 'p';
3242 *out++ = ';';
3243 } else if (*in == '\r') {
3244 if (outend - out < 5) break;
3245 *out++ = '&';
3246 *out++ = '#';
3247 *out++ = '1';
3248 *out++ = '3';
3249 *out++ = ';';
3250 } else {
3251 *out++ = (unsigned char) *in;
3252 }
3253 ++in;
3254 }
3255 *outlen = out - outstart;
3256 *inlen = in - base;
3257 return(0);
3258}
3259
3260/**
3261 * xmlOutputBufferWriteEscape:
3262 * @out: a buffered parser output
3263 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003264 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003265 *
3266 * Write the content of the string in the output I/O buffer
3267 * This routine escapes the caracters and then handle the I18N
3268 * transcoding from internal UTF-8
3269 * The buffer is lossless, i.e. will store in case of partial
3270 * or delayed writes.
3271 *
3272 * Returns the number of chars immediately written, or -1
3273 * in case of error.
3274 */
3275int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003276xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3277 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003278 int nbchars = 0; /* number of chars to output to I/O */
3279 int ret; /* return from function call */
3280 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003281 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003282 int chunk; /* number of byte currently processed from str */
3283 int len; /* number of bytes in str */
3284 int cons; /* byte from str consumed */
3285
Daniel Veillardce244ad2004-11-05 10:03:46 +00003286 if ((out == NULL) || (out->error) || (str == NULL) ||
3287 (out->buffer == NULL) ||
3288 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003289 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003290 if (len < 0) return(0);
3291 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003292 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003293
3294 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003295 oldwritten = written;
3296
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003297 /*
3298 * how many bytes to consume and how many bytes to store.
3299 */
3300 cons = len;
3301 chunk = (out->buffer->size - out->buffer->use) - 1;
3302
3303 /*
3304 * first handle encoding stuff.
3305 */
3306 if (out->encoder != NULL) {
3307 /*
3308 * Store the data in the incoming raw buffer
3309 */
3310 if (out->conv == NULL) {
3311 out->conv = xmlBufferCreate();
3312 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003313 ret = escaping(out->buffer->content + out->buffer->use ,
3314 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003315 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003316 return(-1);
3317 out->buffer->use += chunk;
3318 out->buffer->content[out->buffer->use] = 0;
3319
3320 if ((out->buffer->use < MINLEN) && (cons == len))
3321 goto done;
3322
3323 /*
3324 * convert as much as possible to the output buffer.
3325 */
3326 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3327 if ((ret < 0) && (ret != -3)) {
3328 xmlIOErr(XML_IO_ENCODER, NULL);
3329 out->error = XML_IO_ENCODER;
3330 return(-1);
3331 }
3332 nbchars = out->conv->use;
3333 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003334 ret = escaping(out->buffer->content + out->buffer->use ,
3335 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003336 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003337 return(-1);
3338 out->buffer->use += chunk;
3339 out->buffer->content[out->buffer->use] = 0;
3340 nbchars = out->buffer->use;
3341 }
3342 str += cons;
3343 len -= cons;
3344
3345 if ((nbchars < MINLEN) && (len <= 0))
3346 goto done;
3347
3348 if (out->writecallback) {
3349 /*
3350 * second write the stuff to the I/O channel
3351 */
3352 if (out->encoder != NULL) {
3353 ret = out->writecallback(out->context,
3354 (const char *)out->conv->content, nbchars);
3355 if (ret >= 0)
3356 xmlBufferShrink(out->conv, ret);
3357 } else {
3358 ret = out->writecallback(out->context,
3359 (const char *)out->buffer->content, nbchars);
3360 if (ret >= 0)
3361 xmlBufferShrink(out->buffer, ret);
3362 }
3363 if (ret < 0) {
3364 xmlIOErr(XML_IO_WRITE, NULL);
3365 out->error = XML_IO_WRITE;
3366 return(ret);
3367 }
3368 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003369 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3370 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003371 }
3372 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003373 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003374
3375done:
3376#ifdef DEBUG_INPUT
3377 xmlGenericError(xmlGenericErrorContext,
3378 "I/O: wrote %d chars\n", written);
3379#endif
3380 return(written);
3381}
3382
3383/**
Owen Taylor3473f882001-02-23 17:55:21 +00003384 * xmlOutputBufferWriteString:
3385 * @out: a buffered parser output
3386 * @str: a zero terminated C string
3387 *
3388 * Write the content of the string in the output I/O buffer
3389 * This routine handle the I18N transcoding from internal UTF-8
3390 * The buffer is lossless, i.e. will store in case of partial
3391 * or delayed writes.
3392 *
3393 * Returns the number of chars immediately written, or -1
3394 * in case of error.
3395 */
3396int
3397xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3398 int len;
3399
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003400 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003401 if (str == NULL)
3402 return(-1);
3403 len = strlen(str);
3404
3405 if (len > 0)
3406 return(xmlOutputBufferWrite(out, len, str));
3407 return(len);
3408}
3409
3410/**
3411 * xmlOutputBufferFlush:
3412 * @out: a buffered output
3413 *
3414 * flushes the output I/O channel
3415 *
3416 * Returns the number of byte written or -1 in case of error.
3417 */
3418int
3419xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3420 int nbchars = 0, ret = 0;
3421
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003422 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003423 /*
3424 * first handle encoding stuff.
3425 */
3426 if ((out->conv != NULL) && (out->encoder != NULL)) {
3427 /*
3428 * convert as much as possible to the parser reading buffer.
3429 */
3430 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3431 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003432 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003433 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003434 return(-1);
3435 }
3436 }
3437
3438 /*
3439 * second flush the stuff to the I/O channel
3440 */
3441 if ((out->conv != NULL) && (out->encoder != NULL) &&
3442 (out->writecallback != NULL)) {
3443 ret = out->writecallback(out->context,
3444 (const char *)out->conv->content, out->conv->use);
3445 if (ret >= 0)
3446 xmlBufferShrink(out->conv, ret);
3447 } else if (out->writecallback != NULL) {
3448 ret = out->writecallback(out->context,
3449 (const char *)out->buffer->content, out->buffer->use);
3450 if (ret >= 0)
3451 xmlBufferShrink(out->buffer, ret);
3452 }
3453 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003454 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003455 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003456 return(ret);
3457 }
3458 out->written += ret;
3459
3460#ifdef DEBUG_INPUT
3461 xmlGenericError(xmlGenericErrorContext,
3462 "I/O: flushed %d chars\n", ret);
3463#endif
3464 return(ret);
3465}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003466#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003467
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003468/**
Owen Taylor3473f882001-02-23 17:55:21 +00003469 * xmlParserGetDirectory:
3470 * @filename: the path to a file
3471 *
3472 * lookup the directory for that file
3473 *
3474 * Returns a new allocated string containing the directory, or NULL.
3475 */
3476char *
3477xmlParserGetDirectory(const char *filename) {
3478 char *ret = NULL;
3479 char dir[1024];
3480 char *cur;
3481 char sep = '/';
3482
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003483#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3484 return NULL;
3485#endif
3486
Owen Taylor3473f882001-02-23 17:55:21 +00003487 if (xmlInputCallbackInitialized == 0)
3488 xmlRegisterDefaultInputCallbacks();
3489
3490 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003491#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003492 sep = '\\';
3493#endif
3494
3495 strncpy(dir, filename, 1023);
3496 dir[1023] = 0;
3497 cur = &dir[strlen(dir)];
3498 while (cur > dir) {
3499 if (*cur == sep) break;
3500 cur --;
3501 }
3502 if (*cur == sep) {
3503 if (cur == dir) dir[1] = 0;
3504 else *cur = 0;
3505 ret = xmlMemStrdup(dir);
3506 } else {
3507 if (getcwd(dir, 1024) != NULL) {
3508 dir[1023] = 0;
3509 ret = xmlMemStrdup(dir);
3510 }
3511 }
3512 return(ret);
3513}
3514
3515/****************************************************************
3516 * *
3517 * External entities loading *
3518 * *
3519 ****************************************************************/
3520
Daniel Veillarda840b692003-10-19 13:35:37 +00003521/**
3522 * xmlCheckHTTPInput:
3523 * @ctxt: an XML parser context
3524 * @ret: an XML parser input
3525 *
3526 * Check an input in case it was created from an HTTP stream, in that
3527 * case it will handle encoding and update of the base URL in case of
3528 * redirection. It also checks for HTTP errors in which case the input
3529 * is cleanly freed up and an appropriate error is raised in context
3530 *
3531 * Returns the input or NULL in case of HTTP error.
3532 */
3533xmlParserInputPtr
3534xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3535#ifdef LIBXML_HTTP_ENABLED
3536 if ((ret != NULL) && (ret->buf != NULL) &&
3537 (ret->buf->readcallback == xmlIOHTTPRead) &&
3538 (ret->buf->context != NULL)) {
3539 const char *encoding;
3540 const char *redir;
3541 const char *mime;
3542 int code;
3543
3544 code = xmlNanoHTTPReturnCode(ret->buf->context);
3545 if (code >= 400) {
3546 /* fatal error */
3547 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003548 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003549 (const char *) ret->filename);
3550 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003551 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003552 xmlFreeInputStream(ret);
3553 ret = NULL;
3554 } else {
3555
3556 mime = xmlNanoHTTPMimeType(ret->buf->context);
3557 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3558 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3559 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3560 if (encoding != NULL) {
3561 xmlCharEncodingHandlerPtr handler;
3562
3563 handler = xmlFindCharEncodingHandler(encoding);
3564 if (handler != NULL) {
3565 xmlSwitchInputEncoding(ctxt, ret, handler);
3566 } else {
3567 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3568 "Unknown encoding %s",
3569 BAD_CAST encoding, NULL);
3570 }
3571 if (ret->encoding == NULL)
3572 ret->encoding = xmlStrdup(BAD_CAST encoding);
3573 }
3574#if 0
3575 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3576#endif
3577 }
3578 redir = xmlNanoHTTPRedir(ret->buf->context);
3579 if (redir != NULL) {
3580 if (ret->filename != NULL)
3581 xmlFree((xmlChar *) ret->filename);
3582 if (ret->directory != NULL) {
3583 xmlFree((xmlChar *) ret->directory);
3584 ret->directory = NULL;
3585 }
3586 ret->filename =
3587 (char *) xmlStrdup((const xmlChar *) redir);
3588 }
3589 }
3590 }
3591#endif
3592 return(ret);
3593}
3594
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003595static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003596 const char *path;
3597
3598 if (URL == NULL)
3599 return(0);
3600
Daniel Veillardf4862f02002-09-10 11:13:43 +00003601 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003602#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003603 path = &URL[17];
3604#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003605 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003606#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003607 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003608#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003609 path = &URL[8];
3610#else
3611 path = &URL[7];
3612#endif
3613 } else
3614 path = URL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003615
3616 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003617}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003618
Daniel Veillardad4e2962006-09-21 08:36:38 +00003619#ifdef LIBXML_CATALOG_ENABLED
3620
3621/**
3622 * xmlResolveResourceFromCatalog:
3623 * @URL: the URL for the entity to load
3624 * @ID: the System ID for the entity to load
3625 * @ctxt: the context in which the entity is called or NULL
3626 *
3627 * Resolves the URL and ID against the appropriate catalog.
3628 * This function is used by xmlDefaultExternalEntityLoader and
3629 * xmlNoNetExternalEntityLoader.
3630 *
3631 * Returns a new allocated URL, or NULL.
3632 */
3633xmlChar *
3634xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3635 xmlParserCtxtPtr ctxt) {
3636 xmlChar *resource = NULL;
3637 xmlCatalogAllow pref;
3638
3639 /*
3640 * If the resource doesn't exists as a file,
3641 * try to load it from the resource pointed in the catalogs
3642 */
3643 pref = xmlCatalogGetDefaults();
3644
3645 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3646 /*
3647 * Do a local lookup
3648 */
3649 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3650 ((pref == XML_CATA_ALLOW_ALL) ||
3651 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3652 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3653 (const xmlChar *)ID,
3654 (const xmlChar *)URL);
3655 }
3656 /*
3657 * Try a global lookup
3658 */
3659 if ((resource == NULL) &&
3660 ((pref == XML_CATA_ALLOW_ALL) ||
3661 (pref == XML_CATA_ALLOW_GLOBAL))) {
3662 resource = xmlCatalogResolve((const xmlChar *)ID,
3663 (const xmlChar *)URL);
3664 }
3665 if ((resource == NULL) && (URL != NULL))
3666 resource = xmlStrdup((const xmlChar *) URL);
3667
3668 /*
3669 * TODO: do an URI lookup on the reference
3670 */
3671 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3672 xmlChar *tmp = NULL;
3673
3674 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3675 ((pref == XML_CATA_ALLOW_ALL) ||
3676 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3677 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3678 }
3679 if ((tmp == NULL) &&
3680 ((pref == XML_CATA_ALLOW_ALL) ||
3681 (pref == XML_CATA_ALLOW_GLOBAL))) {
3682 tmp = xmlCatalogResolveURI(resource);
3683 }
3684
3685 if (tmp != NULL) {
3686 xmlFree(resource);
3687 resource = tmp;
3688 }
3689 }
3690 }
3691
3692 return resource;
3693}
3694
3695#endif
3696
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003697/**
Owen Taylor3473f882001-02-23 17:55:21 +00003698 * xmlDefaultExternalEntityLoader:
3699 * @URL: the URL for the entity to load
3700 * @ID: the System ID for the entity to load
3701 * @ctxt: the context in which the entity is called or NULL
3702 *
3703 * By default we don't load external entitites, yet.
3704 *
3705 * Returns a new allocated xmlParserInputPtr, or NULL.
3706 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003707static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003708xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003709 xmlParserCtxtPtr ctxt)
3710{
Owen Taylor3473f882001-02-23 17:55:21 +00003711 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003712 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003713
Owen Taylor3473f882001-02-23 17:55:21 +00003714#ifdef DEBUG_EXTERNAL_ENTITIES
3715 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003716 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003717#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00003718 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3719 int options = ctxt->options;
3720
3721 ctxt->options -= XML_PARSE_NONET;
3722 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3723 ctxt->options = options;
3724 return(ret);
3725 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003726#ifdef LIBXML_CATALOG_ENABLED
3727 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003728#endif
3729
3730 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003731 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003732
3733 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003734 if (ID == NULL)
3735 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003736 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003737 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003738 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003739 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003740 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003741 xmlFree(resource);
3742 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003743}
3744
3745static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3746 xmlDefaultExternalEntityLoader;
3747
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003748/**
Owen Taylor3473f882001-02-23 17:55:21 +00003749 * xmlSetExternalEntityLoader:
3750 * @f: the new entity resolver function
3751 *
3752 * Changes the defaultexternal entity resolver function for the application
3753 */
3754void
3755xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3756 xmlCurrentExternalEntityLoader = f;
3757}
3758
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003759/**
Owen Taylor3473f882001-02-23 17:55:21 +00003760 * xmlGetExternalEntityLoader:
3761 *
3762 * Get the default external entity resolver function for the application
3763 *
3764 * Returns the xmlExternalEntityLoader function pointer
3765 */
3766xmlExternalEntityLoader
3767xmlGetExternalEntityLoader(void) {
3768 return(xmlCurrentExternalEntityLoader);
3769}
3770
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003771/**
Owen Taylor3473f882001-02-23 17:55:21 +00003772 * xmlLoadExternalEntity:
3773 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003774 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003775 * @ctxt: the context in which the entity is called or NULL
3776 *
3777 * Load an external entity, note that the use of this function for
3778 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003779 *
3780 * Returns the xmlParserInputPtr or NULL
3781 */
3782xmlParserInputPtr
3783xmlLoadExternalEntity(const char *URL, const char *ID,
3784 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003785 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003786 char *canonicFilename;
3787 xmlParserInputPtr ret;
3788
3789 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3790 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003791 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003792 return(NULL);
3793 }
3794
3795 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3796 xmlFree(canonicFilename);
3797 return(ret);
3798 }
Owen Taylor3473f882001-02-23 17:55:21 +00003799 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3800}
3801
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003802/************************************************************************
3803 * *
3804 * Disabling Network access *
3805 * *
3806 ************************************************************************/
3807
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003808/**
3809 * xmlNoNetExternalEntityLoader:
3810 * @URL: the URL for the entity to load
3811 * @ID: the System ID for the entity to load
3812 * @ctxt: the context in which the entity is called or NULL
3813 *
3814 * A specific entity loader disabling network accesses, though still
3815 * allowing local catalog accesses for resolution.
3816 *
3817 * Returns a new allocated xmlParserInputPtr, or NULL.
3818 */
3819xmlParserInputPtr
3820xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3821 xmlParserCtxtPtr ctxt) {
3822 xmlParserInputPtr input = NULL;
3823 xmlChar *resource = NULL;
3824
3825#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00003826 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003827#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00003828
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003829 if (resource == NULL)
3830 resource = (xmlChar *) URL;
3831
3832 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003833 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3834 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003835 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003836 if (resource != (xmlChar *) URL)
3837 xmlFree(resource);
3838 return(NULL);
3839 }
3840 }
3841 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3842 if (resource != (xmlChar *) URL)
3843 xmlFree(resource);
3844 return(input);
3845}
3846
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003847#define bottom_xmlIO
3848#include "elfgcchack.h"