blob: fe50a4ea434db676997582d5c6e0d58fd8b2c0b8 [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
Daniel Veillard0da41662006-10-10 09:05:36 +000055# if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillard8ca85b22006-09-01 09:56:07 +000056# define stat _stat
Daniel Veillard0da41662006-10-10 09:05:36 +000057# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000058# endif
Owen Taylor3473f882001-02-23 17:55:21 +000059#endif
60#ifdef HAVE_STAT
61# ifndef S_ISDIR
62# ifdef _S_ISDIR
63# define S_ISDIR(x) _S_ISDIR(x)
64# else
65# ifdef S_IFDIR
66# ifndef S_IFMT
67# ifdef _S_IFMT
68# define S_IFMT _S_IFMT
69# endif
70# endif
71# ifdef S_IFMT
72# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
73# endif
74# endif
75# endif
76# endif
77#endif
78
79#include <libxml/xmlmemory.h>
80#include <libxml/parser.h>
81#include <libxml/parserInternals.h>
82#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000083#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000084#include <libxml/nanohttp.h>
85#include <libxml/nanoftp.h>
86#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000087#ifdef LIBXML_CATALOG_ENABLED
88#include <libxml/catalog.h>
89#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000090#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000091
Daniel Veillardf012a642001-07-23 19:10:52 +000092/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000093/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000094/* #define DEBUG_INPUT */
95
96#ifdef DEBUG_INPUT
97#define MINLEN 40
98#else
99#define MINLEN 4000
100#endif
101
102/*
103 * Input I/O callback sets
104 */
105typedef struct _xmlInputCallback {
106 xmlInputMatchCallback matchcallback;
107 xmlInputOpenCallback opencallback;
108 xmlInputReadCallback readcallback;
109 xmlInputCloseCallback closecallback;
110} xmlInputCallback;
111
112#define MAX_INPUT_CALLBACK 15
113
Daniel Veillard22090732001-07-16 00:06:07 +0000114static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
115static int xmlInputCallbackNr = 0;
116static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000117
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000118#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000119/*
120 * Output I/O callback sets
121 */
122typedef struct _xmlOutputCallback {
123 xmlOutputMatchCallback matchcallback;
124 xmlOutputOpenCallback opencallback;
125 xmlOutputWriteCallback writecallback;
126 xmlOutputCloseCallback closecallback;
127} xmlOutputCallback;
128
129#define MAX_OUTPUT_CALLBACK 15
130
Daniel Veillard22090732001-07-16 00:06:07 +0000131static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
132static int xmlOutputCallbackNr = 0;
133static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000134#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000135
Daniel Veillard05d987b2003-10-08 11:54:57 +0000136/************************************************************************
137 * *
138 * Tree memory error handler *
139 * *
140 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000141
Daniel Veillard05d987b2003-10-08 11:54:57 +0000142static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000143 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000144 "Permission denied", /* EACCES */
145 "Resource temporarily unavailable",/* EAGAIN */
146 "Bad file descriptor", /* EBADF */
147 "Bad message", /* EBADMSG */
148 "Resource busy", /* EBUSY */
149 "Operation canceled", /* ECANCELED */
150 "No child processes", /* ECHILD */
151 "Resource deadlock avoided",/* EDEADLK */
152 "Domain error", /* EDOM */
153 "File exists", /* EEXIST */
154 "Bad address", /* EFAULT */
155 "File too large", /* EFBIG */
156 "Operation in progress", /* EINPROGRESS */
157 "Interrupted function call",/* EINTR */
158 "Invalid argument", /* EINVAL */
159 "Input/output error", /* EIO */
160 "Is a directory", /* EISDIR */
161 "Too many open files", /* EMFILE */
162 "Too many links", /* EMLINK */
163 "Inappropriate message buffer length",/* EMSGSIZE */
164 "Filename too long", /* ENAMETOOLONG */
165 "Too many open files in system",/* ENFILE */
166 "No such device", /* ENODEV */
167 "No such file or directory",/* ENOENT */
168 "Exec format error", /* ENOEXEC */
169 "No locks available", /* ENOLCK */
170 "Not enough space", /* ENOMEM */
171 "No space left on device", /* ENOSPC */
172 "Function not implemented", /* ENOSYS */
173 "Not a directory", /* ENOTDIR */
174 "Directory not empty", /* ENOTEMPTY */
175 "Not supported", /* ENOTSUP */
176 "Inappropriate I/O control operation",/* ENOTTY */
177 "No such device or address",/* ENXIO */
178 "Operation not permitted", /* EPERM */
179 "Broken pipe", /* EPIPE */
180 "Result too large", /* ERANGE */
181 "Read-only file system", /* EROFS */
182 "Invalid seek", /* ESPIPE */
183 "No such process", /* ESRCH */
184 "Operation timed out", /* ETIMEDOUT */
185 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000186 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000187 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000188 "flush error",
189 "write error",
190 "no input",
191 "buffer full",
192 "loading error",
193 "not a socket", /* ENOTSOCK */
194 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000195 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000196 "unreachable network", /* ENETUNREACH */
197 "adddress in use", /* EADDRINUSE */
198 "already in use", /* EALREADY */
199 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000200};
201
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000202#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000203/**
204 * __xmlIOWin32UTF8ToWChar:
205 * @u8String: uft-8 string
206 *
207 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
208 */
209static wchar_t *
210__xmlIOWin32UTF8ToWChar(const char *u8String)
211{
212 wchar_t *wString = NULL;
213
214 if (u8String)
215 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000216 int wLen = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,u8String,-1,NULL,0);
Daniel Veillardf7416012006-04-27 08:15:20 +0000217 if (wLen)
218 {
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000219 wString = xmlMalloc(wLen * sizeof(wchar_t));
Daniel Veillardf7416012006-04-27 08:15:20 +0000220 if (wString)
221 {
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000222 if (MultiByteToWideChar(CP_UTF8,0,u8String,-1,wString,wLen) == 0)
Daniel Veillardf7416012006-04-27 08:15:20 +0000223 {
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000224 xmlFree(wString);
Daniel Veillardf7416012006-04-27 08:15:20 +0000225 wString = NULL;
226 }
227 }
228 }
229 }
230
231 return wString;
232}
233#endif
234
Daniel Veillard05d987b2003-10-08 11:54:57 +0000235/**
236 * xmlIOErrMemory:
237 * @extra: extra informations
238 *
239 * Handle an out of memory condition
240 */
241static void
242xmlIOErrMemory(const char *extra)
243{
244 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
245}
246
247/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000248 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000249 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000250 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000251 * @extra: extra informations
252 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000253 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000254 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000255void
256__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000257{
258 unsigned int idx;
259
260 if (code == 0) {
261#ifdef HAVE_ERRNO_H
262 if (errno == 0) code = 0;
263#ifdef EACCES
264 else if (errno == EACCES) code = XML_IO_EACCES;
265#endif
266#ifdef EAGAIN
267 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
268#endif
269#ifdef EBADF
270 else if (errno == EBADF) code = XML_IO_EBADF;
271#endif
272#ifdef EBADMSG
273 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
274#endif
275#ifdef EBUSY
276 else if (errno == EBUSY) code = XML_IO_EBUSY;
277#endif
278#ifdef ECANCELED
279 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
280#endif
281#ifdef ECHILD
282 else if (errno == ECHILD) code = XML_IO_ECHILD;
283#endif
284#ifdef EDEADLK
285 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
286#endif
287#ifdef EDOM
288 else if (errno == EDOM) code = XML_IO_EDOM;
289#endif
290#ifdef EEXIST
291 else if (errno == EEXIST) code = XML_IO_EEXIST;
292#endif
293#ifdef EFAULT
294 else if (errno == EFAULT) code = XML_IO_EFAULT;
295#endif
296#ifdef EFBIG
297 else if (errno == EFBIG) code = XML_IO_EFBIG;
298#endif
299#ifdef EINPROGRESS
300 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
301#endif
302#ifdef EINTR
303 else if (errno == EINTR) code = XML_IO_EINTR;
304#endif
305#ifdef EINVAL
306 else if (errno == EINVAL) code = XML_IO_EINVAL;
307#endif
308#ifdef EIO
309 else if (errno == EIO) code = XML_IO_EIO;
310#endif
311#ifdef EISDIR
312 else if (errno == EISDIR) code = XML_IO_EISDIR;
313#endif
314#ifdef EMFILE
315 else if (errno == EMFILE) code = XML_IO_EMFILE;
316#endif
317#ifdef EMLINK
318 else if (errno == EMLINK) code = XML_IO_EMLINK;
319#endif
320#ifdef EMSGSIZE
321 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
322#endif
323#ifdef ENAMETOOLONG
324 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
325#endif
326#ifdef ENFILE
327 else if (errno == ENFILE) code = XML_IO_ENFILE;
328#endif
329#ifdef ENODEV
330 else if (errno == ENODEV) code = XML_IO_ENODEV;
331#endif
332#ifdef ENOENT
333 else if (errno == ENOENT) code = XML_IO_ENOENT;
334#endif
335#ifdef ENOEXEC
336 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
337#endif
338#ifdef ENOLCK
339 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
340#endif
341#ifdef ENOMEM
342 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
343#endif
344#ifdef ENOSPC
345 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
346#endif
347#ifdef ENOSYS
348 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
349#endif
350#ifdef ENOTDIR
351 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
352#endif
353#ifdef ENOTEMPTY
354 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
355#endif
356#ifdef ENOTSUP
357 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
358#endif
359#ifdef ENOTTY
360 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
361#endif
362#ifdef ENXIO
363 else if (errno == ENXIO) code = XML_IO_ENXIO;
364#endif
365#ifdef EPERM
366 else if (errno == EPERM) code = XML_IO_EPERM;
367#endif
368#ifdef EPIPE
369 else if (errno == EPIPE) code = XML_IO_EPIPE;
370#endif
371#ifdef ERANGE
372 else if (errno == ERANGE) code = XML_IO_ERANGE;
373#endif
374#ifdef EROFS
375 else if (errno == EROFS) code = XML_IO_EROFS;
376#endif
377#ifdef ESPIPE
378 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
379#endif
380#ifdef ESRCH
381 else if (errno == ESRCH) code = XML_IO_ESRCH;
382#endif
383#ifdef ETIMEDOUT
384 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
385#endif
386#ifdef EXDEV
387 else if (errno == EXDEV) code = XML_IO_EXDEV;
388#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000389#ifdef ENOTSOCK
390 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
391#endif
392#ifdef EISCONN
393 else if (errno == EISCONN) code = XML_IO_EISCONN;
394#endif
395#ifdef ECONNREFUSED
396 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
397#endif
398#ifdef ETIMEDOUT
399 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
400#endif
401#ifdef ENETUNREACH
402 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
403#endif
404#ifdef EADDRINUSE
405 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
406#endif
407#ifdef EINPROGRESS
408 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
409#endif
410#ifdef EALREADY
411 else if (errno == EALREADY) code = XML_IO_EALREADY;
412#endif
413#ifdef EAFNOSUPPORT
414 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
415#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000416 else code = XML_IO_UNKNOWN;
417#endif /* HAVE_ERRNO_H */
418 }
419 idx = 0;
420 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
421 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
422
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000423 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
424}
425
426/**
427 * xmlIOErr:
428 * @code: the error number
429 * @extra: extra informations
430 *
431 * Handle an I/O error
432 */
433static void
434xmlIOErr(int code, const char *extra)
435{
436 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000437}
438
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000439/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000440 * __xmlLoaderErr:
441 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000442 * @extra: extra informations
443 *
444 * Handle a resource access error
445 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000446void
447__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000448{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000449 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000450 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000451 xmlGenericErrorFunc channel = NULL;
452 void *data = NULL;
453 xmlErrorLevel level = XML_ERR_ERROR;
454
Daniel Veillard157fee02003-10-31 10:36:03 +0000455 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
456 (ctxt->instate == XML_PARSER_EOF))
457 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000458 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
459 if (ctxt->validate) {
460 channel = ctxt->sax->error;
461 level = XML_ERR_ERROR;
462 } else {
463 channel = ctxt->sax->warning;
464 level = XML_ERR_WARNING;
465 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000466 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
467 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000468 data = ctxt->userData;
469 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000470 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000471 XML_IO_LOAD_ERROR, level, NULL, 0,
472 filename, NULL, NULL, 0, 0,
473 msg, filename);
474
475}
476
Daniel Veillard05d987b2003-10-08 11:54:57 +0000477/************************************************************************
478 * *
479 * Tree memory error handler *
480 * *
481 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000482/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000483 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000484 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000485 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000486 * This function is obsolete. Please see xmlURIFromPath in uri.c for
487 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000488 *
489 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000490 */
491xmlChar *
492xmlNormalizeWindowsPath(const xmlChar *path)
493{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000494 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000495}
496
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000497/**
498 * xmlCleanupInputCallbacks:
499 *
500 * clears the entire input callback table. this includes the
501 * compiled-in I/O.
502 */
503void
504xmlCleanupInputCallbacks(void)
505{
506 int i;
507
508 if (!xmlInputCallbackInitialized)
509 return;
510
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000511 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000512 xmlInputCallbackTable[i].matchcallback = NULL;
513 xmlInputCallbackTable[i].opencallback = NULL;
514 xmlInputCallbackTable[i].readcallback = NULL;
515 xmlInputCallbackTable[i].closecallback = NULL;
516 }
517
518 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000519 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000520}
521
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000522/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000523 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000524 *
525 * Clear the top input callback from the input stack. this includes the
526 * compiled-in I/O.
527 *
528 * Returns the number of input callback registered or -1 in case of error.
529 */
530int
531xmlPopInputCallbacks(void)
532{
533 if (!xmlInputCallbackInitialized)
534 return(-1);
535
536 if (xmlInputCallbackNr <= 0)
537 return(-1);
538
539 xmlInputCallbackNr--;
540 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
541 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
542 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
543 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
544
545 return(xmlInputCallbackNr);
546}
547
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000548#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000549/**
550 * xmlCleanupOutputCallbacks:
551 *
552 * clears the entire output callback table. this includes the
553 * compiled-in I/O callbacks.
554 */
555void
556xmlCleanupOutputCallbacks(void)
557{
558 int i;
559
560 if (!xmlOutputCallbackInitialized)
561 return;
562
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000563 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000564 xmlOutputCallbackTable[i].matchcallback = NULL;
565 xmlOutputCallbackTable[i].opencallback = NULL;
566 xmlOutputCallbackTable[i].writecallback = NULL;
567 xmlOutputCallbackTable[i].closecallback = NULL;
568 }
569
570 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000571 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000572}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000573#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000574
Owen Taylor3473f882001-02-23 17:55:21 +0000575/************************************************************************
576 * *
577 * Standard I/O for file accesses *
578 * *
579 ************************************************************************/
580
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000581#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
582
583/**
584 * xmlWrapOpenUtf8:
585 * @path: the path in utf-8 encoding
586 * @mode: type of access (0 - read, 1 - write)
587 *
588 * function opens the file specified by @path
589 *
590 */
591static FILE*
592xmlWrapOpenUtf8(const char *path,int mode)
593{
594 FILE *fd = NULL;
595 wchar_t *wPath;
596
597 wPath = __xmlIOWin32UTF8ToWChar(path);
598 if(wPath)
599 {
600 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
601 xmlFree(wPath);
602 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000603 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000604 if(fd == NULL)
605 fd = fopen(path, mode ? "wb" : "rb");
606
607 return fd;
608}
609
610/**
611 * xmlWrapStatUtf8:
612 * @path: the path in utf-8 encoding
613 * @info: structure that stores results
614 *
615 * function obtains information about the file or directory
616 *
617 */
618static int
619xmlWrapStatUtf8(const char *path,struct stat *info)
620{
621#ifdef HAVE_STAT
622 int retval = -1;
623 wchar_t *wPath;
624
625 wPath = __xmlIOWin32UTF8ToWChar(path);
626 if (wPath)
627 {
628 retval = _wstat(wPath,info);
629 xmlFree(wPath);
630 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000631 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000632 if(retval < 0)
633 retval = stat(path,info);
634 return retval;
635#else
636 return -1;
637#endif
638}
639
640/**
641 * xmlWrapOpenNative:
642 * @path: the path
643 * @mode: type of access (0 - read, 1 - write)
644 *
645 * function opens the file specified by @path
646 *
647 */
648static FILE*
649xmlWrapOpenNative(const char *path,int mode)
650{
651 return fopen(path,mode ? "wb" : "rb");
652}
653
654/**
655 * xmlWrapStatNative:
656 * @path: the path
657 * @info: structure that stores results
658 *
659 * function obtains information about the file or directory
660 *
661 */
662static int
663xmlWrapStatNative(const char *path,struct stat *info)
664{
665#ifdef HAVE_STAT
666 return stat(path,info);
667#else
668 return -1;
669#endif
670}
671
672static int (* xmlWrapStat)(const char *,struct stat *) = xmlWrapStatNative;
673static FILE* (* xmlWrapOpen)(const char *,int mode) = xmlWrapOpenNative;
674
675/**
676 * xmlInitPlatformSpecificIo:
677 *
678 * Initialize platform specific features.
679 */
680static void
681xmlInitPlatformSpecificIo
682(void) {
683 static int xmlPlatformIoInitialized = 0;
684 OSVERSIONINFO osvi;
685
686 if(xmlPlatformIoInitialized)
687 return;
688
689 osvi.dwOSVersionInfoSize = sizeof(osvi);
690
691 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
692 xmlWrapStat = xmlWrapStatUtf8;
693 xmlWrapOpen = xmlWrapOpenUtf8;
694 } else {
695 xmlWrapStat = xmlWrapStatNative;
696 xmlWrapOpen = xmlWrapOpenNative;
697 }
698
699 xmlPlatformIoInitialized = 1;
700 return;
701}
702
703#endif
704
Owen Taylor3473f882001-02-23 17:55:21 +0000705/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000706 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000707 * @path: the path to check
708 *
709 * function checks to see if @path is a valid source
710 * (file, socket...) for XML.
711 *
712 * if stat is not available on the target machine,
713 * returns 1. if stat fails, returns 0 (if calling
714 * stat on the filename fails, it can't be right).
715 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000716 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000717 */
718
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000719int
Owen Taylor3473f882001-02-23 17:55:21 +0000720xmlCheckFilename (const char *path)
721{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000722#ifdef HAVE_STAT
Daniel Veillard0b309952006-05-02 20:34:38 +0000723 struct stat stat_buffer;
724#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000725 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000726 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000727
Owen Taylor3473f882001-02-23 17:55:21 +0000728#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000729#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
730 if (xmlWrapStat(path, &stat_buffer) == -1)
731 return 0;
732#else
Owen Taylor3473f882001-02-23 17:55:21 +0000733 if (stat(path, &stat_buffer) == -1)
734 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000735#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000736#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000737 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000738 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000739#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000740#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000741 return 1;
742}
743
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000744static int
Owen Taylor3473f882001-02-23 17:55:21 +0000745xmlNop(void) {
746 return(0);
747}
748
749/**
Owen Taylor3473f882001-02-23 17:55:21 +0000750 * xmlFdRead:
751 * @context: the I/O context
752 * @buffer: where to drop data
753 * @len: number of bytes to read
754 *
755 * Read @len bytes to @buffer from the I/O channel.
756 *
757 * Returns the number of bytes written
758 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000759static int
Owen Taylor3473f882001-02-23 17:55:21 +0000760xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000761 int ret;
762
763 ret = read((int) (long) context, &buffer[0], len);
764 if (ret < 0) xmlIOErr(0, "read()");
765 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000766}
767
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000768#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000769/**
770 * xmlFdWrite:
771 * @context: the I/O context
772 * @buffer: where to get data
773 * @len: number of bytes to write
774 *
775 * Write @len bytes from @buffer to the I/O channel.
776 *
777 * Returns the number of bytes written
778 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000779static int
Owen Taylor3473f882001-02-23 17:55:21 +0000780xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000781 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000782
Daniel Veillard9b693b42005-10-28 14:54:17 +0000783 if (len > 0) {
784 ret = write((int) (long) context, &buffer[0], len);
785 if (ret < 0) xmlIOErr(0, "write()");
786 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000787 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000788}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000789#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000790
791/**
792 * xmlFdClose:
793 * @context: the I/O context
794 *
795 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000796 *
797 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000798 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000799static int
Owen Taylor3473f882001-02-23 17:55:21 +0000800xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000801 int ret;
802 ret = close((int) (long) context);
803 if (ret < 0) xmlIOErr(0, "close()");
804 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000805}
806
807/**
808 * xmlFileMatch:
809 * @filename: the URI for matching
810 *
811 * input from FILE *
812 *
813 * Returns 1 if matches, 0 otherwise
814 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000815int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000816xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000817 return(1);
818}
819
820/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000821 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000822 * @filename: the URI for matching
823 *
824 * input from FILE *, supports compressed input
825 * if @filename is " " then the standard input is used
826 *
827 * Returns an I/O context or NULL in case of error
828 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000829static void *
830xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000831 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000832 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000833
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000834 if (filename == NULL)
835 return(NULL);
836
Owen Taylor3473f882001-02-23 17:55:21 +0000837 if (!strcmp(filename, "-")) {
838 fd = stdin;
839 return((void *) fd);
840 }
841
Daniel Veillardf4862f02002-09-10 11:13:43 +0000842 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000843#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000844 path = &filename[17];
845#else
Owen Taylor3473f882001-02-23 17:55:21 +0000846 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000847#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000848 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000849#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000850 path = &filename[8];
851#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000852 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000853#endif
854 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000855 path = filename;
856
857 if (path == NULL)
858 return(NULL);
859 if (!xmlCheckFilename(path))
860 return(NULL);
861
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000862#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
863 fd = xmlWrapOpen(path, 0);
864#else
865 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000866#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000867 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000868 return((void *) fd);
869}
870
871/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000872 * xmlFileOpen:
873 * @filename: the URI for matching
874 *
875 * Wrapper around xmlFileOpen_real that try it with an unescaped
876 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000877 *
878 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000879 */
880void *
881xmlFileOpen (const char *filename) {
882 char *unescaped;
883 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000884
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000885 unescaped = xmlURIUnescapeString(filename, 0, NULL);
886 if (unescaped != NULL) {
887 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000888 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000889 } else {
890 retval = xmlFileOpen_real(filename);
891 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000892 return retval;
893}
894
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000895#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000896/**
Owen Taylor3473f882001-02-23 17:55:21 +0000897 * xmlFileOpenW:
898 * @filename: the URI for matching
899 *
900 * output to from FILE *,
901 * if @filename is "-" then the standard output is used
902 *
903 * Returns an I/O context or NULL in case of error
904 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000905static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000906xmlFileOpenW (const char *filename) {
907 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000908 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000909
910 if (!strcmp(filename, "-")) {
911 fd = stdout;
912 return((void *) fd);
913 }
914
Daniel Veillardf4862f02002-09-10 11:13:43 +0000915 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000916#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000917 path = &filename[17];
918#else
Owen Taylor3473f882001-02-23 17:55:21 +0000919 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000920#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000921 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000922#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000923 path = &filename[8];
924#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000925 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000926#endif
927 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000928 path = filename;
929
930 if (path == NULL)
931 return(NULL);
932
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000933#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
934 fd = xmlWrapOpen(path, 1);
935#else
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000936 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000937#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000938
Daniel Veillardf7416012006-04-27 08:15:20 +0000939 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000940 return((void *) fd);
941}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000942#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000943
944/**
945 * xmlFileRead:
946 * @context: the I/O context
947 * @buffer: where to drop data
948 * @len: number of bytes to write
949 *
950 * Read @len bytes to @buffer from the I/O channel.
951 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000952 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000953 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000954int
Owen Taylor3473f882001-02-23 17:55:21 +0000955xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000956 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000957 if ((context == NULL) || (buffer == NULL))
958 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000959 ret = fread(&buffer[0], 1, len, (FILE *) context);
960 if (ret < 0) xmlIOErr(0, "fread()");
961 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000962}
963
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000964#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000965/**
966 * xmlFileWrite:
967 * @context: the I/O context
968 * @buffer: where to drop data
969 * @len: number of bytes to write
970 *
971 * Write @len bytes from @buffer to the I/O channel.
972 *
973 * Returns the number of bytes written
974 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000975static int
Owen Taylor3473f882001-02-23 17:55:21 +0000976xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000977 int items;
978
Daniel Veillardce682bc2004-11-05 17:22:25 +0000979 if ((context == NULL) || (buffer == NULL))
980 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000981 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000982 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000983 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000984 return(-1);
985 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000986 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000987}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000988#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000989
990/**
991 * xmlFileClose:
992 * @context: the I/O context
993 *
994 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000995 *
996 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000997 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000998int
Owen Taylor3473f882001-02-23 17:55:21 +0000999xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001000 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001001 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001002
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001003 if (context == NULL)
1004 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001005 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001006 if ((fil == stdout) || (fil == stderr)) {
1007 ret = fflush(fil);
1008 if (ret < 0)
1009 xmlIOErr(0, "fflush()");
1010 return(0);
1011 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001012 if (fil == stdin)
1013 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001014 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1015 if (ret < 0)
1016 xmlIOErr(0, "fclose()");
1017 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001018}
1019
1020/**
1021 * xmlFileFlush:
1022 * @context: the I/O context
1023 *
1024 * Flush an I/O channel
1025 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001026static int
Owen Taylor3473f882001-02-23 17:55:21 +00001027xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001028 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001029
1030 if (context == NULL)
1031 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001032 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1033 if (ret < 0)
1034 xmlIOErr(0, "fflush()");
1035 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001036}
1037
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001038#ifdef LIBXML_OUTPUT_ENABLED
1039/**
1040 * xmlBufferWrite:
1041 * @context: the xmlBuffer
1042 * @buffer: the data to write
1043 * @len: number of bytes to write
1044 *
1045 * Write @len bytes from @buffer to the xml buffer
1046 *
1047 * Returns the number of bytes written
1048 */
1049static int
1050xmlBufferWrite (void * context, const char * buffer, int len) {
1051 int ret;
1052
1053 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1054 if (ret != 0)
1055 return(-1);
1056 return(len);
1057}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001058#endif
1059
Owen Taylor3473f882001-02-23 17:55:21 +00001060#ifdef HAVE_ZLIB_H
1061/************************************************************************
1062 * *
1063 * I/O for compressed file accesses *
1064 * *
1065 ************************************************************************/
1066/**
1067 * xmlGzfileMatch:
1068 * @filename: the URI for matching
1069 *
1070 * input from compressed file test
1071 *
1072 * Returns 1 if matches, 0 otherwise
1073 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001074static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001075xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001076 return(1);
1077}
1078
1079/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001080 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001081 * @filename: the URI for matching
1082 *
1083 * input from compressed file open
1084 * if @filename is " " then the standard input is used
1085 *
1086 * Returns an I/O context or NULL in case of error
1087 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001088static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001089xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001090 const char *path = NULL;
1091 gzFile fd;
1092
1093 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001094 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001095 return((void *) fd);
1096 }
1097
Daniel Veillardf4862f02002-09-10 11:13:43 +00001098 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001099#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001100 path = &filename[17];
1101#else
Owen Taylor3473f882001-02-23 17:55:21 +00001102 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001103#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001104 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001105#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001106 path = &filename[8];
1107#else
Owen Taylor3473f882001-02-23 17:55:21 +00001108 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001109#endif
1110 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001111 path = filename;
1112
1113 if (path == NULL)
1114 return(NULL);
1115 if (!xmlCheckFilename(path))
1116 return(NULL);
1117
1118 fd = gzopen(path, "rb");
1119 return((void *) fd);
1120}
1121
1122/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001123 * xmlGzfileOpen:
1124 * @filename: the URI for matching
1125 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001126 * Wrapper around xmlGzfileOpen if the open fais, it will
1127 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001128 */
1129static void *
1130xmlGzfileOpen (const char *filename) {
1131 char *unescaped;
1132 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001133
1134 retval = xmlGzfileOpen_real(filename);
1135 if (retval == NULL) {
1136 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1137 if (unescaped != NULL) {
1138 retval = xmlGzfileOpen_real(unescaped);
1139 }
1140 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001141 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001142 return retval;
1143}
1144
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001145#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001146/**
Owen Taylor3473f882001-02-23 17:55:21 +00001147 * xmlGzfileOpenW:
1148 * @filename: the URI for matching
1149 * @compression: the compression factor (0 - 9 included)
1150 *
1151 * input from compressed file open
1152 * if @filename is " " then the standard input is used
1153 *
1154 * Returns an I/O context or NULL in case of error
1155 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001156static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001157xmlGzfileOpenW (const char *filename, int compression) {
1158 const char *path = NULL;
1159 char mode[15];
1160 gzFile fd;
1161
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001162 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001163 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001164 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001165 return((void *) fd);
1166 }
1167
Daniel Veillardf4862f02002-09-10 11:13:43 +00001168 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001169#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001170 path = &filename[17];
1171#else
Owen Taylor3473f882001-02-23 17:55:21 +00001172 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001173#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001174 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001175#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001176 path = &filename[8];
1177#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001178 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001179#endif
1180 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001181 path = filename;
1182
1183 if (path == NULL)
1184 return(NULL);
1185
1186 fd = gzopen(path, mode);
1187 return((void *) fd);
1188}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001189#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001190
1191/**
1192 * xmlGzfileRead:
1193 * @context: the I/O context
1194 * @buffer: where to drop data
1195 * @len: number of bytes to write
1196 *
1197 * Read @len bytes to @buffer from the compressed I/O channel.
1198 *
1199 * Returns the number of bytes written
1200 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001201static int
Owen Taylor3473f882001-02-23 17:55:21 +00001202xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001203 int ret;
1204
1205 ret = gzread((gzFile) context, &buffer[0], len);
1206 if (ret < 0) xmlIOErr(0, "gzread()");
1207 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001208}
1209
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001210#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001211/**
1212 * xmlGzfileWrite:
1213 * @context: the I/O context
1214 * @buffer: where to drop data
1215 * @len: number of bytes to write
1216 *
1217 * Write @len bytes from @buffer to the compressed I/O channel.
1218 *
1219 * Returns the number of bytes written
1220 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001221static int
Owen Taylor3473f882001-02-23 17:55:21 +00001222xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001223 int ret;
1224
1225 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1226 if (ret < 0) xmlIOErr(0, "gzwrite()");
1227 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001228}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001229#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001230
1231/**
1232 * xmlGzfileClose:
1233 * @context: the I/O context
1234 *
1235 * Close a compressed I/O channel
1236 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001237static int
Owen Taylor3473f882001-02-23 17:55:21 +00001238xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001239 int ret;
1240
1241 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1242 if (ret < 0) xmlIOErr(0, "gzclose()");
1243 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001244}
1245#endif /* HAVE_ZLIB_H */
1246
1247#ifdef LIBXML_HTTP_ENABLED
1248/************************************************************************
1249 * *
1250 * I/O for HTTP file accesses *
1251 * *
1252 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001253
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001254#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001255typedef struct xmlIOHTTPWriteCtxt_
1256{
1257 int compression;
1258
1259 char * uri;
1260
1261 void * doc_buff;
1262
1263} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1264
1265#ifdef HAVE_ZLIB_H
1266
1267#define DFLT_WBITS ( -15 )
1268#define DFLT_MEM_LVL ( 8 )
1269#define GZ_MAGIC1 ( 0x1f )
1270#define GZ_MAGIC2 ( 0x8b )
1271#define LXML_ZLIB_OS_CODE ( 0x03 )
1272#define INIT_HTTP_BUFF_SIZE ( 32768 )
1273#define DFLT_ZLIB_RATIO ( 5 )
1274
1275/*
1276** Data structure and functions to work with sending compressed data
1277** via HTTP.
1278*/
1279
1280typedef struct xmlZMemBuff_
1281{
1282 unsigned long size;
1283 unsigned long crc;
1284
1285 unsigned char * zbuff;
1286 z_stream zctrl;
1287
1288} xmlZMemBuff, *xmlZMemBuffPtr;
1289
1290/**
1291 * append_reverse_ulong
1292 * @buff: Compressed memory buffer
1293 * @data: Unsigned long to append
1294 *
1295 * Append a unsigned long in reverse byte order to the end of the
1296 * memory buffer.
1297 */
1298static void
1299append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1300
1301 int idx;
1302
1303 if ( buff == NULL )
1304 return;
1305
1306 /*
1307 ** This is plagiarized from putLong in gzio.c (zlib source) where
1308 ** the number "4" is hardcoded. If zlib is ever patched to
1309 ** support 64 bit file sizes, this code would need to be patched
1310 ** as well.
1311 */
1312
1313 for ( idx = 0; idx < 4; idx++ ) {
1314 *buff->zctrl.next_out = ( data & 0xff );
1315 data >>= 8;
1316 buff->zctrl.next_out++;
1317 }
1318
1319 return;
1320}
1321
1322/**
1323 *
1324 * xmlFreeZMemBuff
1325 * @buff: The memory buffer context to clear
1326 *
1327 * Release all the resources associated with the compressed memory buffer.
1328 */
1329static void
1330xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001331
1332#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001333 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001334#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001335
1336 if ( buff == NULL )
1337 return;
1338
1339 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001340#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001341 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001342 if ( z_err != Z_OK )
1343 xmlGenericError( xmlGenericErrorContext,
1344 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1345 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001346#else
1347 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001348#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001349
1350 xmlFree( buff );
1351 return;
1352}
1353
1354/**
1355 * xmlCreateZMemBuff
1356 *@compression: Compression value to use
1357 *
1358 * Create a memory buffer to hold the compressed XML document. The
1359 * compressed document in memory will end up being identical to what
1360 * would be created if gzopen/gzwrite/gzclose were being used to
1361 * write the document to disk. The code for the header/trailer data to
1362 * the compression is plagiarized from the zlib source files.
1363 */
1364static void *
1365xmlCreateZMemBuff( int compression ) {
1366
1367 int z_err;
1368 int hdr_lgth;
1369 xmlZMemBuffPtr buff = NULL;
1370
1371 if ( ( compression < 1 ) || ( compression > 9 ) )
1372 return ( NULL );
1373
1374 /* Create the control and data areas */
1375
1376 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1377 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001378 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001379 return ( NULL );
1380 }
1381
1382 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1383 buff->size = INIT_HTTP_BUFF_SIZE;
1384 buff->zbuff = xmlMalloc( buff->size );
1385 if ( buff->zbuff == NULL ) {
1386 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001387 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001388 return ( NULL );
1389 }
1390
1391 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1392 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1393 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001394 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001395 xmlFreeZMemBuff( buff );
1396 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001397 xmlStrPrintf(msg, 500,
1398 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1399 "Error initializing compression context. ZLIB error:",
1400 z_err );
1401 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001402 return ( NULL );
1403 }
1404
1405 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001406 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001407 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1408 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001409 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1410 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1411 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1412 buff->zctrl.avail_out = buff->size - hdr_lgth;
1413
1414 return ( buff );
1415}
1416
1417/**
1418 * xmlZMemBuffExtend
1419 * @buff: Buffer used to compress and consolidate data.
1420 * @ext_amt: Number of bytes to extend the buffer.
1421 *
1422 * Extend the internal buffer used to store the compressed data by the
1423 * specified amount.
1424 *
1425 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1426 * the original buffer still exists at the original size.
1427 */
1428static int
1429xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1430
1431 int rc = -1;
1432 size_t new_size;
1433 size_t cur_used;
1434
1435 unsigned char * tmp_ptr = NULL;
1436
1437 if ( buff == NULL )
1438 return ( -1 );
1439
1440 else if ( ext_amt == 0 )
1441 return ( 0 );
1442
1443 cur_used = buff->zctrl.next_out - buff->zbuff;
1444 new_size = buff->size + ext_amt;
1445
1446#ifdef DEBUG_HTTP
1447 if ( cur_used > new_size )
1448 xmlGenericError( xmlGenericErrorContext,
1449 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1450 "Buffer overwrite detected during compressed memory",
1451 "buffer extension. Overflowed by",
1452 (cur_used - new_size ) );
1453#endif
1454
1455 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1456 if ( tmp_ptr != NULL ) {
1457 rc = 0;
1458 buff->size = new_size;
1459 buff->zbuff = tmp_ptr;
1460 buff->zctrl.next_out = tmp_ptr + cur_used;
1461 buff->zctrl.avail_out = new_size - cur_used;
1462 }
1463 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001464 xmlChar msg[500];
1465 xmlStrPrintf(msg, 500,
1466 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1467 "Allocation failure extending output buffer to",
1468 new_size );
1469 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001470 }
1471
1472 return ( rc );
1473}
1474
1475/**
1476 * xmlZMemBuffAppend
1477 * @buff: Buffer used to compress and consolidate data
1478 * @src: Uncompressed source content to append to buffer
1479 * @len: Length of source data to append to buffer
1480 *
1481 * Compress and append data to the internal buffer. The data buffer
1482 * will be expanded if needed to store the additional data.
1483 *
1484 * Returns the number of bytes appended to the buffer or -1 on error.
1485 */
1486static int
1487xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1488
1489 int z_err;
1490 size_t min_accept;
1491
1492 if ( ( buff == NULL ) || ( src == NULL ) )
1493 return ( -1 );
1494
1495 buff->zctrl.avail_in = len;
1496 buff->zctrl.next_in = (unsigned char *)src;
1497 while ( buff->zctrl.avail_in > 0 ) {
1498 /*
1499 ** Extend the buffer prior to deflate call if a reasonable amount
1500 ** of output buffer space is not available.
1501 */
1502 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1503 if ( buff->zctrl.avail_out <= min_accept ) {
1504 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1505 return ( -1 );
1506 }
1507
1508 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1509 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001510 xmlChar msg[500];
1511 xmlStrPrintf(msg, 500,
1512 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001513 "Compression error while appending",
1514 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001515 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001516 return ( -1 );
1517 }
1518 }
1519
1520 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1521
1522 return ( len );
1523}
1524
1525/**
1526 * xmlZMemBuffGetContent
1527 * @buff: Compressed memory content buffer
1528 * @data_ref: Pointer reference to point to compressed content
1529 *
1530 * Flushes the compression buffers, appends gzip file trailers and
1531 * returns the compressed content and length of the compressed data.
1532 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1533 *
1534 * Returns the length of the compressed data or -1 on error.
1535 */
1536static int
1537xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1538
1539 int zlgth = -1;
1540 int z_err;
1541
1542 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1543 return ( -1 );
1544
1545 /* Need to loop until compression output buffers are flushed */
1546
1547 do
1548 {
1549 z_err = deflate( &buff->zctrl, Z_FINISH );
1550 if ( z_err == Z_OK ) {
1551 /* In this case Z_OK means more buffer space needed */
1552
1553 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1554 return ( -1 );
1555 }
1556 }
1557 while ( z_err == Z_OK );
1558
1559 /* If the compression state is not Z_STREAM_END, some error occurred */
1560
1561 if ( z_err == Z_STREAM_END ) {
1562
1563 /* Need to append the gzip data trailer */
1564
1565 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1566 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1567 return ( -1 );
1568 }
1569
1570 /*
1571 ** For whatever reason, the CRC and length data are pushed out
1572 ** in reverse byte order. So a memcpy can't be used here.
1573 */
1574
1575 append_reverse_ulong( buff, buff->crc );
1576 append_reverse_ulong( buff, buff->zctrl.total_in );
1577
1578 zlgth = buff->zctrl.next_out - buff->zbuff;
1579 *data_ref = (char *)buff->zbuff;
1580 }
1581
Daniel Veillard05d987b2003-10-08 11:54:57 +00001582 else {
1583 xmlChar msg[500];
1584 xmlStrPrintf(msg, 500,
1585 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1586 "Error flushing zlib buffers. Error code", z_err );
1587 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1588 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001589
1590 return ( zlgth );
1591}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001592#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001593#endif /* HAVE_ZLIB_H */
1594
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001595#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001596/**
1597 * xmlFreeHTTPWriteCtxt
1598 * @ctxt: Context to cleanup
1599 *
1600 * Free allocated memory and reclaim system resources.
1601 *
1602 * No return value.
1603 */
1604static void
1605xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1606{
1607 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001608 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001609
1610 if ( ctxt->doc_buff != NULL ) {
1611
1612#ifdef HAVE_ZLIB_H
1613 if ( ctxt->compression > 0 ) {
1614 xmlFreeZMemBuff( ctxt->doc_buff );
1615 }
1616 else
1617#endif
1618 {
1619 xmlOutputBufferClose( ctxt->doc_buff );
1620 }
1621 }
1622
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001623 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001624 return;
1625}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001626#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001627
1628
Owen Taylor3473f882001-02-23 17:55:21 +00001629/**
1630 * xmlIOHTTPMatch:
1631 * @filename: the URI for matching
1632 *
1633 * check if the URI matches an HTTP one
1634 *
1635 * Returns 1 if matches, 0 otherwise
1636 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001637int
Owen Taylor3473f882001-02-23 17:55:21 +00001638xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001639 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001640 return(1);
1641 return(0);
1642}
1643
1644/**
1645 * xmlIOHTTPOpen:
1646 * @filename: the URI for matching
1647 *
1648 * open an HTTP I/O channel
1649 *
1650 * Returns an I/O context or NULL in case of error
1651 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001652void *
Owen Taylor3473f882001-02-23 17:55:21 +00001653xmlIOHTTPOpen (const char *filename) {
1654 return(xmlNanoHTTPOpen(filename, NULL));
1655}
1656
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001657#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001658/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001659 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001660 * @post_uri: The destination URI for the document
1661 * @compression: The compression desired for the document.
1662 *
1663 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1664 * request. Non-static as is called from the output buffer creation routine.
1665 *
1666 * Returns an I/O context or NULL in case of error.
1667 */
1668
1669void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001670xmlIOHTTPOpenW(const char *post_uri, int compression)
1671{
Daniel Veillardf012a642001-07-23 19:10:52 +00001672
Daniel Veillard572577e2002-01-18 16:23:55 +00001673 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001674
Daniel Veillard572577e2002-01-18 16:23:55 +00001675 if (post_uri == NULL)
1676 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001677
Daniel Veillard572577e2002-01-18 16:23:55 +00001678 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1679 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001680 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001681 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001682 }
1683
Daniel Veillard572577e2002-01-18 16:23:55 +00001684 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001685
Daniel Veillard572577e2002-01-18 16:23:55 +00001686 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1687 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001688 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001689 xmlFreeHTTPWriteCtxt(ctxt);
1690 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001691 }
1692
1693 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001694 * ** Since the document length is required for an HTTP post,
1695 * ** need to put the document into a buffer. A memory buffer
1696 * ** is being used to avoid pushing the data to disk and back.
1697 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001698
1699#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001700 if ((compression > 0) && (compression <= 9)) {
1701
1702 ctxt->compression = compression;
1703 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1704 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001705#endif
1706 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001707 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001708
Daniel Veillard572577e2002-01-18 16:23:55 +00001709 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001710 }
1711
Daniel Veillard572577e2002-01-18 16:23:55 +00001712 if (ctxt->doc_buff == NULL) {
1713 xmlFreeHTTPWriteCtxt(ctxt);
1714 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001715 }
1716
Daniel Veillard572577e2002-01-18 16:23:55 +00001717 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001718}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001719#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001720
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001721#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001722/**
1723 * xmlIOHTTPDfltOpenW
1724 * @post_uri: The destination URI for this document.
1725 *
1726 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1727 * HTTP post command. This function should generally not be used as
1728 * the open callback is short circuited in xmlOutputBufferCreateFile.
1729 *
1730 * Returns a pointer to the new IO context.
1731 */
1732static void *
1733xmlIOHTTPDfltOpenW( const char * post_uri ) {
1734 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1735}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001736#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001737
1738/**
Owen Taylor3473f882001-02-23 17:55:21 +00001739 * xmlIOHTTPRead:
1740 * @context: the I/O context
1741 * @buffer: where to drop data
1742 * @len: number of bytes to write
1743 *
1744 * Read @len bytes to @buffer from the I/O channel.
1745 *
1746 * Returns the number of bytes written
1747 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001748int
Owen Taylor3473f882001-02-23 17:55:21 +00001749xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001750 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001751 return(xmlNanoHTTPRead(context, &buffer[0], len));
1752}
1753
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001754#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001755/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001756 * xmlIOHTTPWrite
1757 * @context: previously opened writing context
1758 * @buffer: data to output to temporary buffer
1759 * @len: bytes to output
1760 *
1761 * Collect data from memory buffer into a temporary file for later
1762 * processing.
1763 *
1764 * Returns number of bytes written.
1765 */
1766
1767static int
1768xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1769
1770 xmlIOHTTPWriteCtxtPtr ctxt = context;
1771
1772 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1773 return ( -1 );
1774
1775 if ( len > 0 ) {
1776
1777 /* Use gzwrite or fwrite as previously setup in the open call */
1778
1779#ifdef HAVE_ZLIB_H
1780 if ( ctxt->compression > 0 )
1781 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1782
1783 else
1784#endif
1785 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1786
1787 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001788 xmlChar msg[500];
1789 xmlStrPrintf(msg, 500,
1790 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001791 "Error appending to internal buffer.",
1792 "Error sending document to URI",
1793 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001794 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001795 }
1796 }
1797
1798 return ( len );
1799}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001800#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001801
1802
1803/**
Owen Taylor3473f882001-02-23 17:55:21 +00001804 * xmlIOHTTPClose:
1805 * @context: the I/O context
1806 *
1807 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001808 *
1809 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001810 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001811int
Owen Taylor3473f882001-02-23 17:55:21 +00001812xmlIOHTTPClose (void * context) {
1813 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001814 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001815}
Daniel Veillardf012a642001-07-23 19:10:52 +00001816
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001817#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001818/**
1819 * xmlIOHTTCloseWrite
1820 * @context: The I/O context
1821 * @http_mthd: The HTTP method to be used when sending the data
1822 *
1823 * Close the transmit HTTP I/O channel and actually send the data.
1824 */
1825static int
1826xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1827
1828 int close_rc = -1;
1829 int http_rtn = 0;
1830 int content_lgth = 0;
1831 xmlIOHTTPWriteCtxtPtr ctxt = context;
1832
1833 char * http_content = NULL;
1834 char * content_encoding = NULL;
1835 char * content_type = (char *) "text/xml";
1836 void * http_ctxt = NULL;
1837
1838 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1839 return ( -1 );
1840
1841 /* Retrieve the content from the appropriate buffer */
1842
1843#ifdef HAVE_ZLIB_H
1844
1845 if ( ctxt->compression > 0 ) {
1846 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1847 content_encoding = (char *) "Content-Encoding: gzip";
1848 }
1849 else
1850#endif
1851 {
1852 /* Pull the data out of the memory output buffer */
1853
1854 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1855 http_content = (char *)dctxt->buffer->content;
1856 content_lgth = dctxt->buffer->use;
1857 }
1858
1859 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001860 xmlChar msg[500];
1861 xmlStrPrintf(msg, 500,
1862 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1863 "Error retrieving content.\nUnable to",
1864 http_mthd, "data to URI", ctxt->uri );
1865 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001866 }
1867
1868 else {
1869
1870 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1871 &content_type, content_encoding,
1872 content_lgth );
1873
1874 if ( http_ctxt != NULL ) {
1875#ifdef DEBUG_HTTP
1876 /* If testing/debugging - dump reply with request content */
1877
1878 FILE * tst_file = NULL;
1879 char buffer[ 4096 ];
1880 char * dump_name = NULL;
1881 int avail;
1882
1883 xmlGenericError( xmlGenericErrorContext,
1884 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1885 http_mthd, ctxt->uri,
1886 xmlNanoHTTPReturnCode( http_ctxt ) );
1887
1888 /*
1889 ** Since either content or reply may be gzipped,
1890 ** dump them to separate files instead of the
1891 ** standard error context.
1892 */
1893
1894 dump_name = tempnam( NULL, "lxml" );
1895 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001896 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001897
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001898 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001899 if ( tst_file != NULL ) {
1900 xmlGenericError( xmlGenericErrorContext,
1901 "Transmitted content saved in file: %s\n", buffer );
1902
1903 fwrite( http_content, sizeof( char ),
1904 content_lgth, tst_file );
1905 fclose( tst_file );
1906 }
1907
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001908 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001909 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001910 if ( tst_file != NULL ) {
1911 xmlGenericError( xmlGenericErrorContext,
1912 "Reply content saved in file: %s\n", buffer );
1913
1914
1915 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1916 buffer, sizeof( buffer ) )) > 0 ) {
1917
1918 fwrite( buffer, sizeof( char ), avail, tst_file );
1919 }
1920
1921 fclose( tst_file );
1922 }
1923
1924 free( dump_name );
1925 }
1926#endif /* DEBUG_HTTP */
1927
1928 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1929 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1930 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001931 else {
1932 xmlChar msg[500];
1933 xmlStrPrintf(msg, 500,
1934 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001935 http_mthd, content_lgth,
1936 "bytes to URI", ctxt->uri,
1937 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001938 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1939 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001940
1941 xmlNanoHTTPClose( http_ctxt );
1942 xmlFree( content_type );
1943 }
1944 }
1945
1946 /* Final cleanups */
1947
1948 xmlFreeHTTPWriteCtxt( ctxt );
1949
1950 return ( close_rc );
1951}
1952
1953/**
1954 * xmlIOHTTPClosePut
1955 *
1956 * @context: The I/O context
1957 *
1958 * Close the transmit HTTP I/O channel and actually send data using a PUT
1959 * HTTP method.
1960 */
1961static int
1962xmlIOHTTPClosePut( void * ctxt ) {
1963 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1964}
1965
1966
1967/**
1968 * xmlIOHTTPClosePost
1969 *
1970 * @context: The I/O context
1971 *
1972 * Close the transmit HTTP I/O channel and actually send data using a POST
1973 * HTTP method.
1974 */
1975static int
1976xmlIOHTTPClosePost( void * ctxt ) {
1977 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1978}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001979#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001980
Owen Taylor3473f882001-02-23 17:55:21 +00001981#endif /* LIBXML_HTTP_ENABLED */
1982
1983#ifdef LIBXML_FTP_ENABLED
1984/************************************************************************
1985 * *
1986 * I/O for FTP file accesses *
1987 * *
1988 ************************************************************************/
1989/**
1990 * xmlIOFTPMatch:
1991 * @filename: the URI for matching
1992 *
1993 * check if the URI matches an FTP one
1994 *
1995 * Returns 1 if matches, 0 otherwise
1996 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001997int
Owen Taylor3473f882001-02-23 17:55:21 +00001998xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001999 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002000 return(1);
2001 return(0);
2002}
2003
2004/**
2005 * xmlIOFTPOpen:
2006 * @filename: the URI for matching
2007 *
2008 * open an FTP I/O channel
2009 *
2010 * Returns an I/O context or NULL in case of error
2011 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002012void *
Owen Taylor3473f882001-02-23 17:55:21 +00002013xmlIOFTPOpen (const char *filename) {
2014 return(xmlNanoFTPOpen(filename));
2015}
2016
2017/**
2018 * xmlIOFTPRead:
2019 * @context: the I/O context
2020 * @buffer: where to drop data
2021 * @len: number of bytes to write
2022 *
2023 * Read @len bytes to @buffer from the I/O channel.
2024 *
2025 * Returns the number of bytes written
2026 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002027int
Owen Taylor3473f882001-02-23 17:55:21 +00002028xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002029 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002030 return(xmlNanoFTPRead(context, &buffer[0], len));
2031}
2032
2033/**
2034 * xmlIOFTPClose:
2035 * @context: the I/O context
2036 *
2037 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002038 *
2039 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002040 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002041int
Owen Taylor3473f882001-02-23 17:55:21 +00002042xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002043 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002044}
2045#endif /* LIBXML_FTP_ENABLED */
2046
2047
2048/**
2049 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002050 * @matchFunc: the xmlInputMatchCallback
2051 * @openFunc: the xmlInputOpenCallback
2052 * @readFunc: the xmlInputReadCallback
2053 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002054 *
2055 * Register a new set of I/O callback for handling parser input.
2056 *
2057 * Returns the registered handler number or -1 in case of error
2058 */
2059int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002060xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2061 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2062 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002063 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2064 return(-1);
2065 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002066 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2067 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2068 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2069 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002070 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002071 return(xmlInputCallbackNr++);
2072}
2073
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002074#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002075/**
2076 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002077 * @matchFunc: the xmlOutputMatchCallback
2078 * @openFunc: the xmlOutputOpenCallback
2079 * @writeFunc: the xmlOutputWriteCallback
2080 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002081 *
2082 * Register a new set of I/O callback for handling output.
2083 *
2084 * Returns the registered handler number or -1 in case of error
2085 */
2086int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002087xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2088 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2089 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002090 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
2091 return(-1);
2092 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002093 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2094 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2095 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2096 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002097 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002098 return(xmlOutputCallbackNr++);
2099}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002100#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002101
2102/**
2103 * xmlRegisterDefaultInputCallbacks:
2104 *
2105 * Registers the default compiled-in I/O handlers.
2106 */
2107void
Owen Taylor3473f882001-02-23 17:55:21 +00002108xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002109(void) {
2110 if (xmlInputCallbackInitialized)
2111 return;
2112
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002113#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2114 xmlInitPlatformSpecificIo();
2115#endif
2116
Owen Taylor3473f882001-02-23 17:55:21 +00002117 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2118 xmlFileRead, xmlFileClose);
2119#ifdef HAVE_ZLIB_H
2120 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2121 xmlGzfileRead, xmlGzfileClose);
2122#endif /* HAVE_ZLIB_H */
2123
2124#ifdef LIBXML_HTTP_ENABLED
2125 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2126 xmlIOHTTPRead, xmlIOHTTPClose);
2127#endif /* LIBXML_HTTP_ENABLED */
2128
2129#ifdef LIBXML_FTP_ENABLED
2130 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2131 xmlIOFTPRead, xmlIOFTPClose);
2132#endif /* LIBXML_FTP_ENABLED */
2133 xmlInputCallbackInitialized = 1;
2134}
2135
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002136#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002137/**
2138 * xmlRegisterDefaultOutputCallbacks:
2139 *
2140 * Registers the default compiled-in I/O handlers.
2141 */
2142void
Owen Taylor3473f882001-02-23 17:55:21 +00002143xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002144(void) {
2145 if (xmlOutputCallbackInitialized)
2146 return;
2147
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002148#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2149 xmlInitPlatformSpecificIo();
2150#endif
2151
Owen Taylor3473f882001-02-23 17:55:21 +00002152 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2153 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002154
2155#ifdef LIBXML_HTTP_ENABLED
2156 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2157 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2158#endif
2159
Owen Taylor3473f882001-02-23 17:55:21 +00002160/*********************************
2161 No way a-priori to distinguish between gzipped files from
2162 uncompressed ones except opening if existing then closing
2163 and saving with same compression ratio ... a pain.
2164
2165#ifdef HAVE_ZLIB_H
2166 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2167 xmlGzfileWrite, xmlGzfileClose);
2168#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002169
2170 Nor FTP PUT ....
2171#ifdef LIBXML_FTP_ENABLED
2172 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2173 xmlIOFTPWrite, xmlIOFTPClose);
2174#endif
2175 **********************************/
2176 xmlOutputCallbackInitialized = 1;
2177}
2178
Daniel Veillardf012a642001-07-23 19:10:52 +00002179#ifdef LIBXML_HTTP_ENABLED
2180/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002181 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002182 *
2183 * By default, libxml submits HTTP output requests using the "PUT" method.
2184 * Calling this method changes the HTTP output method to use the "POST"
2185 * method instead.
2186 *
2187 */
2188void
2189xmlRegisterHTTPPostCallbacks( void ) {
2190
2191 /* Register defaults if not done previously */
2192
2193 if ( xmlOutputCallbackInitialized == 0 )
2194 xmlRegisterDefaultOutputCallbacks( );
2195
2196 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2197 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2198 return;
2199}
2200#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002201#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002202
Owen Taylor3473f882001-02-23 17:55:21 +00002203/**
2204 * xmlAllocParserInputBuffer:
2205 * @enc: the charset encoding if known
2206 *
2207 * Create a buffered parser input for progressive parsing
2208 *
2209 * Returns the new parser input or NULL
2210 */
2211xmlParserInputBufferPtr
2212xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2213 xmlParserInputBufferPtr ret;
2214
2215 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2216 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002217 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002218 return(NULL);
2219 }
2220 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002221 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002222 if (ret->buffer == NULL) {
2223 xmlFree(ret);
2224 return(NULL);
2225 }
2226 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2227 ret->encoder = xmlGetCharEncodingHandler(enc);
2228 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002229 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002230 else
2231 ret->raw = NULL;
2232 ret->readcallback = NULL;
2233 ret->closecallback = NULL;
2234 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002235 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002236 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002237
2238 return(ret);
2239}
2240
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002241#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002242/**
2243 * xmlAllocOutputBuffer:
2244 * @encoder: the encoding converter or NULL
2245 *
2246 * Create a buffered parser output
2247 *
2248 * Returns the new parser output or NULL
2249 */
2250xmlOutputBufferPtr
2251xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2252 xmlOutputBufferPtr ret;
2253
2254 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2255 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002256 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002257 return(NULL);
2258 }
2259 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2260 ret->buffer = xmlBufferCreate();
2261 if (ret->buffer == NULL) {
2262 xmlFree(ret);
2263 return(NULL);
2264 }
2265 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2266 ret->encoder = encoder;
2267 if (encoder != NULL) {
2268 ret->conv = xmlBufferCreateSize(4000);
2269 /*
2270 * This call is designed to initiate the encoder state
2271 */
2272 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2273 } else
2274 ret->conv = NULL;
2275 ret->writecallback = NULL;
2276 ret->closecallback = NULL;
2277 ret->context = NULL;
2278 ret->written = 0;
2279
2280 return(ret);
2281}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002282#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002283
2284/**
2285 * xmlFreeParserInputBuffer:
2286 * @in: a buffered parser input
2287 *
2288 * Free up the memory used by a buffered parser input
2289 */
2290void
2291xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002292 if (in == NULL) return;
2293
Owen Taylor3473f882001-02-23 17:55:21 +00002294 if (in->raw) {
2295 xmlBufferFree(in->raw);
2296 in->raw = NULL;
2297 }
2298 if (in->encoder != NULL) {
2299 xmlCharEncCloseFunc(in->encoder);
2300 }
2301 if (in->closecallback != NULL) {
2302 in->closecallback(in->context);
2303 }
2304 if (in->buffer != NULL) {
2305 xmlBufferFree(in->buffer);
2306 in->buffer = NULL;
2307 }
2308
Owen Taylor3473f882001-02-23 17:55:21 +00002309 xmlFree(in);
2310}
2311
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002312#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002313/**
2314 * xmlOutputBufferClose:
2315 * @out: a buffered output
2316 *
2317 * flushes and close the output I/O channel
2318 * and free up all the associated resources
2319 *
2320 * Returns the number of byte written or -1 in case of error.
2321 */
2322int
Daniel Veillard828ce832003-10-08 19:19:10 +00002323xmlOutputBufferClose(xmlOutputBufferPtr out)
2324{
Owen Taylor3473f882001-02-23 17:55:21 +00002325 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002326 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002327
2328 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002329 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002330 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002331 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002332 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002333 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002334 }
2335 written = out->written;
2336 if (out->conv) {
2337 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002338 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002339 }
2340 if (out->encoder != NULL) {
2341 xmlCharEncCloseFunc(out->encoder);
2342 }
2343 if (out->buffer != NULL) {
2344 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002345 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002346 }
2347
Daniel Veillard828ce832003-10-08 19:19:10 +00002348 if (out->error)
2349 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002350 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002351 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002352}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002353#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002354
Daniel Veillard1b243b42004-06-08 10:16:42 +00002355xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002356__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002357 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002358 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002359 void *context = NULL;
2360
2361 if (xmlInputCallbackInitialized == 0)
2362 xmlRegisterDefaultInputCallbacks();
2363
2364 if (URI == NULL) return(NULL);
2365
2366 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002367 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002368 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002369 */
2370 if (context == NULL) {
2371 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2372 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2373 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002374 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002375 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002376 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002377 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002378 }
Owen Taylor3473f882001-02-23 17:55:21 +00002379 }
2380 }
2381 if (context == NULL) {
2382 return(NULL);
2383 }
2384
2385 /*
2386 * Allocate the Input buffer front-end.
2387 */
2388 ret = xmlAllocParserInputBuffer(enc);
2389 if (ret != NULL) {
2390 ret->context = context;
2391 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2392 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002393#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002394 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2395 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002396 if (((z_stream *)context)->avail_in > 4) {
2397 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002398 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002399 if (gzread(context, buff4, 4) == 4) {
2400 if (strncmp(buff4, cptr, 4) == 0)
2401 ret->compressed = 0;
2402 else
2403 ret->compressed = 1;
2404 gzrewind(context);
2405 }
2406 }
2407 }
2408#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002409 }
William M. Brack42331a92004-07-29 07:07:16 +00002410 else
2411 xmlInputCallbackTable[i].closecallback (context);
2412
Owen Taylor3473f882001-02-23 17:55:21 +00002413 return(ret);
2414}
2415
2416/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002417 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002418 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002419 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002420 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002421 * Create a buffered parser input for the progressive parsing of a file
2422 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002423 * Automatic support for ZLIB/Compress compressed document is provided
2424 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002425 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002426 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002427 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002428 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002429xmlParserInputBufferPtr
2430xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2431 if ((xmlParserInputBufferCreateFilenameValue)) {
2432 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2433 }
2434 return __xmlParserInputBufferCreateFilename(URI, enc);
2435}
2436
2437#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002438xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002439__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002440 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002441 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002442 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002443 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002444 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002445 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002446 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002447#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002448 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002449#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002450
Owen Taylor3473f882001-02-23 17:55:21 +00002451 if (xmlOutputCallbackInitialized == 0)
2452 xmlRegisterDefaultOutputCallbacks();
2453
2454 if (URI == NULL) return(NULL);
2455
Daniel Veillard966a31e2004-05-09 02:58:44 +00002456 puri = xmlParseURI(URI);
2457 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002458#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002459 if ((puri->scheme != NULL) &&
2460 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002461 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002462#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002463 /*
2464 * try to limit the damages of the URI unescaping code.
2465 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002466 if ((puri->scheme == NULL) ||
2467 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002468 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2469 xmlFreeURI(puri);
2470 }
Owen Taylor3473f882001-02-23 17:55:21 +00002471
2472 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002473 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002474 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002475 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002476 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002477 if (unescaped != NULL) {
2478#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002479 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002480 context = xmlGzfileOpenW(unescaped, compression);
2481 if (context != NULL) {
2482 ret = xmlAllocOutputBuffer(encoder);
2483 if (ret != NULL) {
2484 ret->context = context;
2485 ret->writecallback = xmlGzfileWrite;
2486 ret->closecallback = xmlGzfileClose;
2487 }
2488 xmlFree(unescaped);
2489 return(ret);
2490 }
2491 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002492#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002493 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2494 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2495 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2496#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2497 /* Need to pass compression parameter into HTTP open calls */
2498 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2499 context = xmlIOHTTPOpenW(unescaped, compression);
2500 else
2501#endif
2502 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2503 if (context != NULL)
2504 break;
2505 }
2506 }
2507 xmlFree(unescaped);
2508 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002509
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002510 /*
2511 * If this failed try with a non-escaped URI this may be a strange
2512 * filename
2513 */
2514 if (context == NULL) {
2515#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002516 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002517 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002518 if (context != NULL) {
2519 ret = xmlAllocOutputBuffer(encoder);
2520 if (ret != NULL) {
2521 ret->context = context;
2522 ret->writecallback = xmlGzfileWrite;
2523 ret->closecallback = xmlGzfileClose;
2524 }
2525 return(ret);
2526 }
2527 }
2528#endif
2529 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2530 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002531 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002532#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2533 /* Need to pass compression parameter into HTTP open calls */
2534 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2535 context = xmlIOHTTPOpenW(URI, compression);
2536 else
2537#endif
2538 context = xmlOutputCallbackTable[i].opencallback(URI);
2539 if (context != NULL)
2540 break;
2541 }
Owen Taylor3473f882001-02-23 17:55:21 +00002542 }
2543 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002544
Owen Taylor3473f882001-02-23 17:55:21 +00002545 if (context == NULL) {
2546 return(NULL);
2547 }
2548
2549 /*
2550 * Allocate the Output buffer front-end.
2551 */
2552 ret = xmlAllocOutputBuffer(encoder);
2553 if (ret != NULL) {
2554 ret->context = context;
2555 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2556 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2557 }
2558 return(ret);
2559}
Daniel Veillard0335a842004-06-02 16:18:40 +00002560
2561/**
2562 * xmlOutputBufferCreateFilename:
2563 * @URI: a C string containing the URI or filename
2564 * @encoder: the encoding converter or NULL
2565 * @compression: the compression ration (0 none, 9 max).
2566 *
2567 * Create a buffered output for the progressive saving of a file
2568 * If filename is "-' then we use stdout as the output.
2569 * Automatic support for ZLIB/Compress compressed document is provided
2570 * by default if found at compile-time.
2571 * TODO: currently if compression is set, the library only support
2572 * writing to a local file.
2573 *
2574 * Returns the new output or NULL
2575 */
2576xmlOutputBufferPtr
2577xmlOutputBufferCreateFilename(const char *URI,
2578 xmlCharEncodingHandlerPtr encoder,
2579 int compression ATTRIBUTE_UNUSED) {
2580 if ((xmlOutputBufferCreateFilenameValue)) {
2581 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2582 }
2583 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2584}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002585#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002586
2587/**
2588 * xmlParserInputBufferCreateFile:
2589 * @file: a FILE*
2590 * @enc: the charset encoding if known
2591 *
2592 * Create a buffered parser input for the progressive parsing of a FILE *
2593 * buffered C I/O
2594 *
2595 * Returns the new parser input or NULL
2596 */
2597xmlParserInputBufferPtr
2598xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2599 xmlParserInputBufferPtr ret;
2600
2601 if (xmlInputCallbackInitialized == 0)
2602 xmlRegisterDefaultInputCallbacks();
2603
2604 if (file == NULL) return(NULL);
2605
2606 ret = xmlAllocParserInputBuffer(enc);
2607 if (ret != NULL) {
2608 ret->context = file;
2609 ret->readcallback = xmlFileRead;
2610 ret->closecallback = xmlFileFlush;
2611 }
2612
2613 return(ret);
2614}
2615
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002616#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002617/**
2618 * xmlOutputBufferCreateFile:
2619 * @file: a FILE*
2620 * @encoder: the encoding converter or NULL
2621 *
2622 * Create a buffered output for the progressive saving to a FILE *
2623 * buffered C I/O
2624 *
2625 * Returns the new parser output or NULL
2626 */
2627xmlOutputBufferPtr
2628xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2629 xmlOutputBufferPtr ret;
2630
2631 if (xmlOutputCallbackInitialized == 0)
2632 xmlRegisterDefaultOutputCallbacks();
2633
2634 if (file == NULL) return(NULL);
2635
2636 ret = xmlAllocOutputBuffer(encoder);
2637 if (ret != NULL) {
2638 ret->context = file;
2639 ret->writecallback = xmlFileWrite;
2640 ret->closecallback = xmlFileFlush;
2641 }
2642
2643 return(ret);
2644}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002645
2646/**
2647 * xmlOutputBufferCreateBuffer:
2648 * @buffer: a xmlBufferPtr
2649 * @encoder: the encoding converter or NULL
2650 *
2651 * Create a buffered output for the progressive saving to a xmlBuffer
2652 *
2653 * Returns the new parser output or NULL
2654 */
2655xmlOutputBufferPtr
2656xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2657 xmlCharEncodingHandlerPtr encoder) {
2658 xmlOutputBufferPtr ret;
2659
2660 if (buffer == NULL) return(NULL);
2661
Rob Richardsa44f2342005-11-09 18:03:45 +00002662 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2663 xmlBufferWrite,
2664 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002665 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002666
2667 return(ret);
2668}
2669
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002670#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002671
2672/**
2673 * xmlParserInputBufferCreateFd:
2674 * @fd: a file descriptor number
2675 * @enc: the charset encoding if known
2676 *
2677 * Create a buffered parser input for the progressive parsing for the input
2678 * from a file descriptor
2679 *
2680 * Returns the new parser input or NULL
2681 */
2682xmlParserInputBufferPtr
2683xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2684 xmlParserInputBufferPtr ret;
2685
2686 if (fd < 0) return(NULL);
2687
2688 ret = xmlAllocParserInputBuffer(enc);
2689 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002690 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002691 ret->readcallback = xmlFdRead;
2692 ret->closecallback = xmlFdClose;
2693 }
2694
2695 return(ret);
2696}
2697
2698/**
2699 * xmlParserInputBufferCreateMem:
2700 * @mem: the memory input
2701 * @size: the length of the memory block
2702 * @enc: the charset encoding if known
2703 *
2704 * Create a buffered parser input for the progressive parsing for the input
2705 * from a memory area.
2706 *
2707 * Returns the new parser input or NULL
2708 */
2709xmlParserInputBufferPtr
2710xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2711 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002712 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002713
2714 if (size <= 0) return(NULL);
2715 if (mem == NULL) return(NULL);
2716
2717 ret = xmlAllocParserInputBuffer(enc);
2718 if (ret != NULL) {
2719 ret->context = (void *) mem;
2720 ret->readcallback = (xmlInputReadCallback) xmlNop;
2721 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002722 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2723 if (errcode != 0) {
2724 xmlFree(ret);
2725 return(NULL);
2726 }
Owen Taylor3473f882001-02-23 17:55:21 +00002727 }
2728
2729 return(ret);
2730}
2731
2732/**
Daniel Veillard53350552003-09-18 13:35:51 +00002733 * xmlParserInputBufferCreateStatic:
2734 * @mem: the memory input
2735 * @size: the length of the memory block
2736 * @enc: the charset encoding if known
2737 *
2738 * Create a buffered parser input for the progressive parsing for the input
2739 * from an immutable memory area. This will not copy the memory area to
2740 * the buffer, but the memory is expected to be available until the end of
2741 * the parsing, this is useful for example when using mmap'ed file.
2742 *
2743 * Returns the new parser input or NULL
2744 */
2745xmlParserInputBufferPtr
2746xmlParserInputBufferCreateStatic(const char *mem, int size,
2747 xmlCharEncoding enc) {
2748 xmlParserInputBufferPtr ret;
2749
2750 if (size <= 0) return(NULL);
2751 if (mem == NULL) return(NULL);
2752
2753 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2754 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002755 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002756 return(NULL);
2757 }
2758 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002759 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002760 if (ret->buffer == NULL) {
2761 xmlFree(ret);
2762 return(NULL);
2763 }
2764 ret->encoder = xmlGetCharEncodingHandler(enc);
2765 if (ret->encoder != NULL)
2766 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2767 else
2768 ret->raw = NULL;
2769 ret->compressed = -1;
2770 ret->context = (void *) mem;
2771 ret->readcallback = NULL;
2772 ret->closecallback = NULL;
2773
2774 return(ret);
2775}
2776
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002777#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002778/**
Owen Taylor3473f882001-02-23 17:55:21 +00002779 * xmlOutputBufferCreateFd:
2780 * @fd: a file descriptor number
2781 * @encoder: the encoding converter or NULL
2782 *
2783 * Create a buffered output for the progressive saving
2784 * to a file descriptor
2785 *
2786 * Returns the new parser output or NULL
2787 */
2788xmlOutputBufferPtr
2789xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2790 xmlOutputBufferPtr ret;
2791
2792 if (fd < 0) return(NULL);
2793
2794 ret = xmlAllocOutputBuffer(encoder);
2795 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002796 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002797 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002798 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002799 }
2800
2801 return(ret);
2802}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002803#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002804
2805/**
2806 * xmlParserInputBufferCreateIO:
2807 * @ioread: an I/O read function
2808 * @ioclose: an I/O close function
2809 * @ioctx: an I/O handler
2810 * @enc: the charset encoding if known
2811 *
2812 * Create a buffered parser input for the progressive parsing for the input
2813 * from an I/O handler
2814 *
2815 * Returns the new parser input or NULL
2816 */
2817xmlParserInputBufferPtr
2818xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2819 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2820 xmlParserInputBufferPtr ret;
2821
2822 if (ioread == NULL) return(NULL);
2823
2824 ret = xmlAllocParserInputBuffer(enc);
2825 if (ret != NULL) {
2826 ret->context = (void *) ioctx;
2827 ret->readcallback = ioread;
2828 ret->closecallback = ioclose;
2829 }
2830
2831 return(ret);
2832}
2833
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002834#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002835/**
2836 * xmlOutputBufferCreateIO:
2837 * @iowrite: an I/O write function
2838 * @ioclose: an I/O close function
2839 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002840 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002841 *
2842 * Create a buffered output for the progressive saving
2843 * to an I/O handler
2844 *
2845 * Returns the new parser output or NULL
2846 */
2847xmlOutputBufferPtr
2848xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2849 xmlOutputCloseCallback ioclose, void *ioctx,
2850 xmlCharEncodingHandlerPtr encoder) {
2851 xmlOutputBufferPtr ret;
2852
2853 if (iowrite == NULL) return(NULL);
2854
2855 ret = xmlAllocOutputBuffer(encoder);
2856 if (ret != NULL) {
2857 ret->context = (void *) ioctx;
2858 ret->writecallback = iowrite;
2859 ret->closecallback = ioclose;
2860 }
2861
2862 return(ret);
2863}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002864#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002865
2866/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002867 * xmlParserInputBufferCreateFilenameDefault:
2868 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2869 *
2870 * Registers a callback for URI input file handling
2871 *
2872 * Returns the old value of the registration function
2873 */
2874xmlParserInputBufferCreateFilenameFunc
2875xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2876{
2877 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2878 if (old == NULL) {
2879 old = __xmlParserInputBufferCreateFilename;
2880 }
2881
2882 xmlParserInputBufferCreateFilenameValue = func;
2883 return(old);
2884}
2885
2886/**
2887 * xmlOutputBufferCreateFilenameDefault:
2888 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2889 *
2890 * Registers a callback for URI output file handling
2891 *
2892 * Returns the old value of the registration function
2893 */
2894xmlOutputBufferCreateFilenameFunc
2895xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2896{
2897 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2898#ifdef LIBXML_OUTPUT_ENABLED
2899 if (old == NULL) {
2900 old = __xmlOutputBufferCreateFilename;
2901 }
2902#endif
2903 xmlOutputBufferCreateFilenameValue = func;
2904 return(old);
2905}
2906
2907/**
Owen Taylor3473f882001-02-23 17:55:21 +00002908 * xmlParserInputBufferPush:
2909 * @in: a buffered parser input
2910 * @len: the size in bytes of the array.
2911 * @buf: an char array
2912 *
2913 * Push the content of the arry in the input buffer
2914 * This routine handle the I18N transcoding to internal UTF-8
2915 * This is used when operating the parser in progressive (push) mode.
2916 *
2917 * Returns the number of chars read and stored in the buffer, or -1
2918 * in case of error.
2919 */
2920int
2921xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2922 int len, const char *buf) {
2923 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002924 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002925
2926 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002927 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002928 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002929 unsigned int use;
2930
Owen Taylor3473f882001-02-23 17:55:21 +00002931 /*
2932 * Store the data in the incoming raw buffer
2933 */
2934 if (in->raw == NULL) {
2935 in->raw = xmlBufferCreate();
2936 }
William M. Bracka3215c72004-07-31 16:24:01 +00002937 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2938 if (ret != 0)
2939 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002940
2941 /*
2942 * convert as much as possible to the parser reading buffer.
2943 */
Daniel Veillard36711902004-02-11 13:25:26 +00002944 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002945 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2946 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002947 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002948 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002949 return(-1);
2950 }
Daniel Veillard36711902004-02-11 13:25:26 +00002951 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002952 } else {
2953 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002954 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2955 if (ret != 0)
2956 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002957 }
2958#ifdef DEBUG_INPUT
2959 xmlGenericError(xmlGenericErrorContext,
2960 "I/O: pushed %d chars, buffer %d/%d\n",
2961 nbchars, in->buffer->use, in->buffer->size);
2962#endif
2963 return(nbchars);
2964}
2965
2966/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002967 * endOfInput:
2968 *
2969 * When reading from an Input channel indicated end of file or error
2970 * don't reread from it again.
2971 */
2972static int
2973endOfInput (void * context ATTRIBUTE_UNUSED,
2974 char * buffer ATTRIBUTE_UNUSED,
2975 int len ATTRIBUTE_UNUSED) {
2976 return(0);
2977}
2978
2979/**
Owen Taylor3473f882001-02-23 17:55:21 +00002980 * xmlParserInputBufferGrow:
2981 * @in: a buffered parser input
2982 * @len: indicative value of the amount of chars to read
2983 *
2984 * Grow up the content of the input buffer, the old data are preserved
2985 * This routine handle the I18N transcoding to internal UTF-8
2986 * This routine is used when operating the parser in normal (pull) mode
2987 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002988 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002989 * onto in->buffer or in->raw
2990 *
2991 * Returns the number of chars read and stored in the buffer, or -1
2992 * in case of error.
2993 */
2994int
2995xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2996 char *buffer = NULL;
2997 int res = 0;
2998 int nbchars = 0;
2999 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00003000 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00003001
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003002 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003003 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003004 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003005
Owen Taylor3473f882001-02-23 17:55:21 +00003006 buffree = in->buffer->size - in->buffer->use;
3007 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003008 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003009 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003010 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003011 }
Owen Taylor3473f882001-02-23 17:55:21 +00003012
Daniel Veillarde5354492002-05-16 08:43:22 +00003013 needSize = in->buffer->use + len + 1;
3014 if (needSize > in->buffer->size){
3015 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003016 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003017 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003018 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003019 }
Owen Taylor3473f882001-02-23 17:55:21 +00003020 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003021 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003022
3023 /*
3024 * Call the read method for this I/O type.
3025 */
3026 if (in->readcallback != NULL) {
3027 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003028 if (res <= 0)
3029 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003030 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003031 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003032 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003033 return(-1);
3034 }
3035 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003036 return(-1);
3037 }
3038 len = res;
3039 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003040 unsigned int use;
3041
Owen Taylor3473f882001-02-23 17:55:21 +00003042 /*
3043 * Store the data in the incoming raw buffer
3044 */
3045 if (in->raw == NULL) {
3046 in->raw = xmlBufferCreate();
3047 }
William M. Bracka3215c72004-07-31 16:24:01 +00003048 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3049 if (res != 0)
3050 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003051
3052 /*
3053 * convert as much as possible to the parser reading buffer.
3054 */
Daniel Veillard36711902004-02-11 13:25:26 +00003055 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003056 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3057 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003058 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003059 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003060 return(-1);
3061 }
Daniel Veillard36711902004-02-11 13:25:26 +00003062 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003063 } else {
3064 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00003065 in->buffer->use += nbchars;
3066 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003067 }
3068#ifdef DEBUG_INPUT
3069 xmlGenericError(xmlGenericErrorContext,
3070 "I/O: read %d chars, buffer %d/%d\n",
3071 nbchars, in->buffer->use, in->buffer->size);
3072#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003073 return(nbchars);
3074}
3075
3076/**
3077 * xmlParserInputBufferRead:
3078 * @in: a buffered parser input
3079 * @len: indicative value of the amount of chars to read
3080 *
3081 * Refresh the content of the input buffer, the old data are considered
3082 * consumed
3083 * This routine handle the I18N transcoding to internal UTF-8
3084 *
3085 * Returns the number of chars read and stored in the buffer, or -1
3086 * in case of error.
3087 */
3088int
3089xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003090 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003091 if (in->readcallback != NULL)
3092 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003093 else if ((in->buffer != NULL) &&
3094 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3095 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003096 else
3097 return(-1);
3098}
3099
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003100#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003101/**
3102 * xmlOutputBufferWrite:
3103 * @out: a buffered parser output
3104 * @len: the size in bytes of the array.
3105 * @buf: an char array
3106 *
3107 * Write the content of the array in the output I/O buffer
3108 * This routine handle the I18N transcoding from internal UTF-8
3109 * The buffer is lossless, i.e. will store in case of partial
3110 * or delayed writes.
3111 *
3112 * Returns the number of chars immediately written, or -1
3113 * in case of error.
3114 */
3115int
3116xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3117 int nbchars = 0; /* number of chars to output to I/O */
3118 int ret; /* return from function call */
3119 int written = 0; /* number of char written to I/O so far */
3120 int chunk; /* number of byte curreent processed from buf */
3121
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003122 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003123 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003124 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003125
3126 do {
3127 chunk = len;
3128 if (chunk > 4 * MINLEN)
3129 chunk = 4 * MINLEN;
3130
3131 /*
3132 * first handle encoding stuff.
3133 */
3134 if (out->encoder != NULL) {
3135 /*
3136 * Store the data in the incoming raw buffer
3137 */
3138 if (out->conv == NULL) {
3139 out->conv = xmlBufferCreate();
3140 }
William M. Bracka3215c72004-07-31 16:24:01 +00003141 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3142 if (ret != 0)
3143 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003144
3145 if ((out->buffer->use < MINLEN) && (chunk == len))
3146 goto done;
3147
3148 /*
3149 * convert as much as possible to the parser reading buffer.
3150 */
3151 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003152 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003153 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003154 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003155 return(-1);
3156 }
3157 nbchars = out->conv->use;
3158 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003159 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3160 if (ret != 0)
3161 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003162 nbchars = out->buffer->use;
3163 }
3164 buf += chunk;
3165 len -= chunk;
3166
3167 if ((nbchars < MINLEN) && (len <= 0))
3168 goto done;
3169
3170 if (out->writecallback) {
3171 /*
3172 * second write the stuff to the I/O channel
3173 */
3174 if (out->encoder != NULL) {
3175 ret = out->writecallback(out->context,
3176 (const char *)out->conv->content, nbchars);
3177 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003178 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003179 } else {
3180 ret = out->writecallback(out->context,
3181 (const char *)out->buffer->content, nbchars);
3182 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003183 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003184 }
3185 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003186 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003187 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003188 return(ret);
3189 }
3190 out->written += ret;
3191 }
3192 written += nbchars;
3193 } while (len > 0);
3194
3195done:
3196#ifdef DEBUG_INPUT
3197 xmlGenericError(xmlGenericErrorContext,
3198 "I/O: wrote %d chars\n", written);
3199#endif
3200 return(written);
3201}
3202
3203/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003204 * xmlEscapeContent:
3205 * @out: a pointer to an array of bytes to store the result
3206 * @outlen: the length of @out
3207 * @in: a pointer to an array of unescaped UTF-8 bytes
3208 * @inlen: the length of @in
3209 *
3210 * Take a block of UTF-8 chars in and escape them.
3211 * Returns 0 if success, or -1 otherwise
3212 * The value of @inlen after return is the number of octets consumed
3213 * if the return value is positive, else unpredictable.
3214 * The value of @outlen after return is the number of octets consumed.
3215 */
3216static int
3217xmlEscapeContent(unsigned char* out, int *outlen,
3218 const xmlChar* in, int *inlen) {
3219 unsigned char* outstart = out;
3220 const unsigned char* base = in;
3221 unsigned char* outend = out + *outlen;
3222 const unsigned char* inend;
3223
3224 inend = in + (*inlen);
3225
3226 while ((in < inend) && (out < outend)) {
3227 if (*in == '<') {
3228 if (outend - out < 4) break;
3229 *out++ = '&';
3230 *out++ = 'l';
3231 *out++ = 't';
3232 *out++ = ';';
3233 } else if (*in == '>') {
3234 if (outend - out < 4) break;
3235 *out++ = '&';
3236 *out++ = 'g';
3237 *out++ = 't';
3238 *out++ = ';';
3239 } else if (*in == '&') {
3240 if (outend - out < 5) break;
3241 *out++ = '&';
3242 *out++ = 'a';
3243 *out++ = 'm';
3244 *out++ = 'p';
3245 *out++ = ';';
3246 } else if (*in == '\r') {
3247 if (outend - out < 5) break;
3248 *out++ = '&';
3249 *out++ = '#';
3250 *out++ = '1';
3251 *out++ = '3';
3252 *out++ = ';';
3253 } else {
3254 *out++ = (unsigned char) *in;
3255 }
3256 ++in;
3257 }
3258 *outlen = out - outstart;
3259 *inlen = in - base;
3260 return(0);
3261}
3262
3263/**
3264 * xmlOutputBufferWriteEscape:
3265 * @out: a buffered parser output
3266 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003267 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003268 *
3269 * Write the content of the string in the output I/O buffer
3270 * This routine escapes the caracters and then handle the I18N
3271 * transcoding from internal UTF-8
3272 * The buffer is lossless, i.e. will store in case of partial
3273 * or delayed writes.
3274 *
3275 * Returns the number of chars immediately written, or -1
3276 * in case of error.
3277 */
3278int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003279xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3280 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003281 int nbchars = 0; /* number of chars to output to I/O */
3282 int ret; /* return from function call */
3283 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003284 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003285 int chunk; /* number of byte currently processed from str */
3286 int len; /* number of bytes in str */
3287 int cons; /* byte from str consumed */
3288
Daniel Veillardce244ad2004-11-05 10:03:46 +00003289 if ((out == NULL) || (out->error) || (str == NULL) ||
3290 (out->buffer == NULL) ||
3291 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003292 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003293 if (len < 0) return(0);
3294 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003295 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003296
3297 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003298 oldwritten = written;
3299
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003300 /*
3301 * how many bytes to consume and how many bytes to store.
3302 */
3303 cons = len;
3304 chunk = (out->buffer->size - out->buffer->use) - 1;
3305
3306 /*
3307 * first handle encoding stuff.
3308 */
3309 if (out->encoder != NULL) {
3310 /*
3311 * Store the data in the incoming raw buffer
3312 */
3313 if (out->conv == NULL) {
3314 out->conv = xmlBufferCreate();
3315 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003316 ret = escaping(out->buffer->content + out->buffer->use ,
3317 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003318 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003319 return(-1);
3320 out->buffer->use += chunk;
3321 out->buffer->content[out->buffer->use] = 0;
3322
3323 if ((out->buffer->use < MINLEN) && (cons == len))
3324 goto done;
3325
3326 /*
3327 * convert as much as possible to the output buffer.
3328 */
3329 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3330 if ((ret < 0) && (ret != -3)) {
3331 xmlIOErr(XML_IO_ENCODER, NULL);
3332 out->error = XML_IO_ENCODER;
3333 return(-1);
3334 }
3335 nbchars = out->conv->use;
3336 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003337 ret = escaping(out->buffer->content + out->buffer->use ,
3338 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003339 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003340 return(-1);
3341 out->buffer->use += chunk;
3342 out->buffer->content[out->buffer->use] = 0;
3343 nbchars = out->buffer->use;
3344 }
3345 str += cons;
3346 len -= cons;
3347
3348 if ((nbchars < MINLEN) && (len <= 0))
3349 goto done;
3350
3351 if (out->writecallback) {
3352 /*
3353 * second write the stuff to the I/O channel
3354 */
3355 if (out->encoder != NULL) {
3356 ret = out->writecallback(out->context,
3357 (const char *)out->conv->content, nbchars);
3358 if (ret >= 0)
3359 xmlBufferShrink(out->conv, ret);
3360 } else {
3361 ret = out->writecallback(out->context,
3362 (const char *)out->buffer->content, nbchars);
3363 if (ret >= 0)
3364 xmlBufferShrink(out->buffer, ret);
3365 }
3366 if (ret < 0) {
3367 xmlIOErr(XML_IO_WRITE, NULL);
3368 out->error = XML_IO_WRITE;
3369 return(ret);
3370 }
3371 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003372 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3373 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003374 }
3375 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003376 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003377
3378done:
3379#ifdef DEBUG_INPUT
3380 xmlGenericError(xmlGenericErrorContext,
3381 "I/O: wrote %d chars\n", written);
3382#endif
3383 return(written);
3384}
3385
3386/**
Owen Taylor3473f882001-02-23 17:55:21 +00003387 * xmlOutputBufferWriteString:
3388 * @out: a buffered parser output
3389 * @str: a zero terminated C string
3390 *
3391 * Write the content of the string in the output I/O buffer
3392 * This routine handle the I18N transcoding from internal UTF-8
3393 * The buffer is lossless, i.e. will store in case of partial
3394 * or delayed writes.
3395 *
3396 * Returns the number of chars immediately written, or -1
3397 * in case of error.
3398 */
3399int
3400xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3401 int len;
3402
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003403 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003404 if (str == NULL)
3405 return(-1);
3406 len = strlen(str);
3407
3408 if (len > 0)
3409 return(xmlOutputBufferWrite(out, len, str));
3410 return(len);
3411}
3412
3413/**
3414 * xmlOutputBufferFlush:
3415 * @out: a buffered output
3416 *
3417 * flushes the output I/O channel
3418 *
3419 * Returns the number of byte written or -1 in case of error.
3420 */
3421int
3422xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3423 int nbchars = 0, ret = 0;
3424
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003425 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003426 /*
3427 * first handle encoding stuff.
3428 */
3429 if ((out->conv != NULL) && (out->encoder != NULL)) {
3430 /*
3431 * convert as much as possible to the parser reading buffer.
3432 */
3433 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3434 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003435 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003436 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003437 return(-1);
3438 }
3439 }
3440
3441 /*
3442 * second flush the stuff to the I/O channel
3443 */
3444 if ((out->conv != NULL) && (out->encoder != NULL) &&
3445 (out->writecallback != NULL)) {
3446 ret = out->writecallback(out->context,
3447 (const char *)out->conv->content, out->conv->use);
3448 if (ret >= 0)
3449 xmlBufferShrink(out->conv, ret);
3450 } else if (out->writecallback != NULL) {
3451 ret = out->writecallback(out->context,
3452 (const char *)out->buffer->content, out->buffer->use);
3453 if (ret >= 0)
3454 xmlBufferShrink(out->buffer, ret);
3455 }
3456 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003457 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003458 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003459 return(ret);
3460 }
3461 out->written += ret;
3462
3463#ifdef DEBUG_INPUT
3464 xmlGenericError(xmlGenericErrorContext,
3465 "I/O: flushed %d chars\n", ret);
3466#endif
3467 return(ret);
3468}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003469#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003470
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003471/**
Owen Taylor3473f882001-02-23 17:55:21 +00003472 * xmlParserGetDirectory:
3473 * @filename: the path to a file
3474 *
3475 * lookup the directory for that file
3476 *
3477 * Returns a new allocated string containing the directory, or NULL.
3478 */
3479char *
3480xmlParserGetDirectory(const char *filename) {
3481 char *ret = NULL;
3482 char dir[1024];
3483 char *cur;
3484 char sep = '/';
3485
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003486#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3487 return NULL;
3488#endif
3489
Owen Taylor3473f882001-02-23 17:55:21 +00003490 if (xmlInputCallbackInitialized == 0)
3491 xmlRegisterDefaultInputCallbacks();
3492
3493 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003494#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003495 sep = '\\';
3496#endif
3497
3498 strncpy(dir, filename, 1023);
3499 dir[1023] = 0;
3500 cur = &dir[strlen(dir)];
3501 while (cur > dir) {
3502 if (*cur == sep) break;
3503 cur --;
3504 }
3505 if (*cur == sep) {
3506 if (cur == dir) dir[1] = 0;
3507 else *cur = 0;
3508 ret = xmlMemStrdup(dir);
3509 } else {
3510 if (getcwd(dir, 1024) != NULL) {
3511 dir[1023] = 0;
3512 ret = xmlMemStrdup(dir);
3513 }
3514 }
3515 return(ret);
3516}
3517
3518/****************************************************************
3519 * *
3520 * External entities loading *
3521 * *
3522 ****************************************************************/
3523
Daniel Veillarda840b692003-10-19 13:35:37 +00003524/**
3525 * xmlCheckHTTPInput:
3526 * @ctxt: an XML parser context
3527 * @ret: an XML parser input
3528 *
3529 * Check an input in case it was created from an HTTP stream, in that
3530 * case it will handle encoding and update of the base URL in case of
3531 * redirection. It also checks for HTTP errors in which case the input
3532 * is cleanly freed up and an appropriate error is raised in context
3533 *
3534 * Returns the input or NULL in case of HTTP error.
3535 */
3536xmlParserInputPtr
3537xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3538#ifdef LIBXML_HTTP_ENABLED
3539 if ((ret != NULL) && (ret->buf != NULL) &&
3540 (ret->buf->readcallback == xmlIOHTTPRead) &&
3541 (ret->buf->context != NULL)) {
3542 const char *encoding;
3543 const char *redir;
3544 const char *mime;
3545 int code;
3546
3547 code = xmlNanoHTTPReturnCode(ret->buf->context);
3548 if (code >= 400) {
3549 /* fatal error */
3550 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003551 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003552 (const char *) ret->filename);
3553 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003554 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003555 xmlFreeInputStream(ret);
3556 ret = NULL;
3557 } else {
3558
3559 mime = xmlNanoHTTPMimeType(ret->buf->context);
3560 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3561 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3562 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3563 if (encoding != NULL) {
3564 xmlCharEncodingHandlerPtr handler;
3565
3566 handler = xmlFindCharEncodingHandler(encoding);
3567 if (handler != NULL) {
3568 xmlSwitchInputEncoding(ctxt, ret, handler);
3569 } else {
3570 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3571 "Unknown encoding %s",
3572 BAD_CAST encoding, NULL);
3573 }
3574 if (ret->encoding == NULL)
3575 ret->encoding = xmlStrdup(BAD_CAST encoding);
3576 }
3577#if 0
3578 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3579#endif
3580 }
3581 redir = xmlNanoHTTPRedir(ret->buf->context);
3582 if (redir != NULL) {
3583 if (ret->filename != NULL)
3584 xmlFree((xmlChar *) ret->filename);
3585 if (ret->directory != NULL) {
3586 xmlFree((xmlChar *) ret->directory);
3587 ret->directory = NULL;
3588 }
3589 ret->filename =
3590 (char *) xmlStrdup((const xmlChar *) redir);
3591 }
3592 }
3593 }
3594#endif
3595 return(ret);
3596}
3597
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003598static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003599 const char *path;
3600
3601 if (URL == NULL)
3602 return(0);
3603
Daniel Veillardf4862f02002-09-10 11:13:43 +00003604 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003605#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003606 path = &URL[17];
3607#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003608 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003609#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003610 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003611#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003612 path = &URL[8];
3613#else
3614 path = &URL[7];
3615#endif
3616 } else
3617 path = URL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003618
3619 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003620}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003621
Daniel Veillardad4e2962006-09-21 08:36:38 +00003622#ifdef LIBXML_CATALOG_ENABLED
3623
3624/**
3625 * xmlResolveResourceFromCatalog:
3626 * @URL: the URL for the entity to load
3627 * @ID: the System ID for the entity to load
3628 * @ctxt: the context in which the entity is called or NULL
3629 *
3630 * Resolves the URL and ID against the appropriate catalog.
3631 * This function is used by xmlDefaultExternalEntityLoader and
3632 * xmlNoNetExternalEntityLoader.
3633 *
3634 * Returns a new allocated URL, or NULL.
3635 */
3636xmlChar *
3637xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3638 xmlParserCtxtPtr ctxt) {
3639 xmlChar *resource = NULL;
3640 xmlCatalogAllow pref;
3641
3642 /*
3643 * If the resource doesn't exists as a file,
3644 * try to load it from the resource pointed in the catalogs
3645 */
3646 pref = xmlCatalogGetDefaults();
3647
3648 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3649 /*
3650 * Do a local lookup
3651 */
3652 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3653 ((pref == XML_CATA_ALLOW_ALL) ||
3654 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3655 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3656 (const xmlChar *)ID,
3657 (const xmlChar *)URL);
3658 }
3659 /*
3660 * Try a global lookup
3661 */
3662 if ((resource == NULL) &&
3663 ((pref == XML_CATA_ALLOW_ALL) ||
3664 (pref == XML_CATA_ALLOW_GLOBAL))) {
3665 resource = xmlCatalogResolve((const xmlChar *)ID,
3666 (const xmlChar *)URL);
3667 }
3668 if ((resource == NULL) && (URL != NULL))
3669 resource = xmlStrdup((const xmlChar *) URL);
3670
3671 /*
3672 * TODO: do an URI lookup on the reference
3673 */
3674 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3675 xmlChar *tmp = NULL;
3676
3677 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3678 ((pref == XML_CATA_ALLOW_ALL) ||
3679 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3680 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3681 }
3682 if ((tmp == NULL) &&
3683 ((pref == XML_CATA_ALLOW_ALL) ||
3684 (pref == XML_CATA_ALLOW_GLOBAL))) {
3685 tmp = xmlCatalogResolveURI(resource);
3686 }
3687
3688 if (tmp != NULL) {
3689 xmlFree(resource);
3690 resource = tmp;
3691 }
3692 }
3693 }
3694
3695 return resource;
3696}
3697
3698#endif
3699
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003700/**
Owen Taylor3473f882001-02-23 17:55:21 +00003701 * xmlDefaultExternalEntityLoader:
3702 * @URL: the URL for the entity to load
3703 * @ID: the System ID for the entity to load
3704 * @ctxt: the context in which the entity is called or NULL
3705 *
3706 * By default we don't load external entitites, yet.
3707 *
3708 * Returns a new allocated xmlParserInputPtr, or NULL.
3709 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003710static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003711xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003712 xmlParserCtxtPtr ctxt)
3713{
Owen Taylor3473f882001-02-23 17:55:21 +00003714 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003715 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003716
Owen Taylor3473f882001-02-23 17:55:21 +00003717#ifdef DEBUG_EXTERNAL_ENTITIES
3718 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003719 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003720#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00003721 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3722 int options = ctxt->options;
3723
3724 ctxt->options -= XML_PARSE_NONET;
3725 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3726 ctxt->options = options;
3727 return(ret);
3728 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003729#ifdef LIBXML_CATALOG_ENABLED
3730 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003731#endif
3732
3733 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003734 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003735
3736 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003737 if (ID == NULL)
3738 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003739 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003740 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003741 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003742 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003743 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003744 xmlFree(resource);
3745 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003746}
3747
3748static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3749 xmlDefaultExternalEntityLoader;
3750
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003751/**
Owen Taylor3473f882001-02-23 17:55:21 +00003752 * xmlSetExternalEntityLoader:
3753 * @f: the new entity resolver function
3754 *
3755 * Changes the defaultexternal entity resolver function for the application
3756 */
3757void
3758xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3759 xmlCurrentExternalEntityLoader = f;
3760}
3761
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003762/**
Owen Taylor3473f882001-02-23 17:55:21 +00003763 * xmlGetExternalEntityLoader:
3764 *
3765 * Get the default external entity resolver function for the application
3766 *
3767 * Returns the xmlExternalEntityLoader function pointer
3768 */
3769xmlExternalEntityLoader
3770xmlGetExternalEntityLoader(void) {
3771 return(xmlCurrentExternalEntityLoader);
3772}
3773
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003774/**
Owen Taylor3473f882001-02-23 17:55:21 +00003775 * xmlLoadExternalEntity:
3776 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003777 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003778 * @ctxt: the context in which the entity is called or NULL
3779 *
3780 * Load an external entity, note that the use of this function for
3781 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003782 *
3783 * Returns the xmlParserInputPtr or NULL
3784 */
3785xmlParserInputPtr
3786xmlLoadExternalEntity(const char *URL, const char *ID,
3787 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003788 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003789 char *canonicFilename;
3790 xmlParserInputPtr ret;
3791
3792 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3793 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003794 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003795 return(NULL);
3796 }
3797
3798 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3799 xmlFree(canonicFilename);
3800 return(ret);
3801 }
Owen Taylor3473f882001-02-23 17:55:21 +00003802 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3803}
3804
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003805/************************************************************************
3806 * *
3807 * Disabling Network access *
3808 * *
3809 ************************************************************************/
3810
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003811/**
3812 * xmlNoNetExternalEntityLoader:
3813 * @URL: the URL for the entity to load
3814 * @ID: the System ID for the entity to load
3815 * @ctxt: the context in which the entity is called or NULL
3816 *
3817 * A specific entity loader disabling network accesses, though still
3818 * allowing local catalog accesses for resolution.
3819 *
3820 * Returns a new allocated xmlParserInputPtr, or NULL.
3821 */
3822xmlParserInputPtr
3823xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3824 xmlParserCtxtPtr ctxt) {
3825 xmlParserInputPtr input = NULL;
3826 xmlChar *resource = NULL;
3827
3828#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00003829 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003830#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00003831
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003832 if (resource == NULL)
3833 resource = (xmlChar *) URL;
3834
3835 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003836 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3837 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003838 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003839 if (resource != (xmlChar *) URL)
3840 xmlFree(resource);
3841 return(NULL);
3842 }
3843 }
3844 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3845 if (resource != (xmlChar *) URL)
3846 xmlFree(resource);
3847 return(input);
3848}
3849
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003850#define bottom_xmlIO
3851#include "elfgcchack.h"