blob: 081de2c05f6f0f4faffd1b8ad72f06dc18b6d857 [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{
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000212 wchar_t *wString = NULL;
Daniel Veillardf7416012006-04-27 08:15:20 +0000213
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000214 if (u8String) {
215 int wLen =
216 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
217 -1, NULL, 0);
218 if (wLen) {
219 wString = xmlMalloc(wLen * sizeof(wchar_t));
220 if (wString) {
221 if (MultiByteToWideChar
222 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
223 xmlFree(wString);
224 wString = NULL;
225 }
226 }
227 }
228 }
229
230 return wString;
Daniel Veillardf7416012006-04-27 08:15:20 +0000231}
232#endif
233
Daniel Veillard05d987b2003-10-08 11:54:57 +0000234/**
235 * xmlIOErrMemory:
236 * @extra: extra informations
237 *
238 * Handle an out of memory condition
239 */
240static void
241xmlIOErrMemory(const char *extra)
242{
243 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
244}
245
246/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000247 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000248 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000249 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000250 * @extra: extra informations
251 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000252 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000253 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000254void
255__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000256{
257 unsigned int idx;
258
259 if (code == 0) {
260#ifdef HAVE_ERRNO_H
261 if (errno == 0) code = 0;
262#ifdef EACCES
263 else if (errno == EACCES) code = XML_IO_EACCES;
264#endif
265#ifdef EAGAIN
266 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
267#endif
268#ifdef EBADF
269 else if (errno == EBADF) code = XML_IO_EBADF;
270#endif
271#ifdef EBADMSG
272 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
273#endif
274#ifdef EBUSY
275 else if (errno == EBUSY) code = XML_IO_EBUSY;
276#endif
277#ifdef ECANCELED
278 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
279#endif
280#ifdef ECHILD
281 else if (errno == ECHILD) code = XML_IO_ECHILD;
282#endif
283#ifdef EDEADLK
284 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
285#endif
286#ifdef EDOM
287 else if (errno == EDOM) code = XML_IO_EDOM;
288#endif
289#ifdef EEXIST
290 else if (errno == EEXIST) code = XML_IO_EEXIST;
291#endif
292#ifdef EFAULT
293 else if (errno == EFAULT) code = XML_IO_EFAULT;
294#endif
295#ifdef EFBIG
296 else if (errno == EFBIG) code = XML_IO_EFBIG;
297#endif
298#ifdef EINPROGRESS
299 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
300#endif
301#ifdef EINTR
302 else if (errno == EINTR) code = XML_IO_EINTR;
303#endif
304#ifdef EINVAL
305 else if (errno == EINVAL) code = XML_IO_EINVAL;
306#endif
307#ifdef EIO
308 else if (errno == EIO) code = XML_IO_EIO;
309#endif
310#ifdef EISDIR
311 else if (errno == EISDIR) code = XML_IO_EISDIR;
312#endif
313#ifdef EMFILE
314 else if (errno == EMFILE) code = XML_IO_EMFILE;
315#endif
316#ifdef EMLINK
317 else if (errno == EMLINK) code = XML_IO_EMLINK;
318#endif
319#ifdef EMSGSIZE
320 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
321#endif
322#ifdef ENAMETOOLONG
323 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
324#endif
325#ifdef ENFILE
326 else if (errno == ENFILE) code = XML_IO_ENFILE;
327#endif
328#ifdef ENODEV
329 else if (errno == ENODEV) code = XML_IO_ENODEV;
330#endif
331#ifdef ENOENT
332 else if (errno == ENOENT) code = XML_IO_ENOENT;
333#endif
334#ifdef ENOEXEC
335 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
336#endif
337#ifdef ENOLCK
338 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
339#endif
340#ifdef ENOMEM
341 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
342#endif
343#ifdef ENOSPC
344 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
345#endif
346#ifdef ENOSYS
347 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
348#endif
349#ifdef ENOTDIR
350 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
351#endif
352#ifdef ENOTEMPTY
353 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
354#endif
355#ifdef ENOTSUP
356 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
357#endif
358#ifdef ENOTTY
359 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
360#endif
361#ifdef ENXIO
362 else if (errno == ENXIO) code = XML_IO_ENXIO;
363#endif
364#ifdef EPERM
365 else if (errno == EPERM) code = XML_IO_EPERM;
366#endif
367#ifdef EPIPE
368 else if (errno == EPIPE) code = XML_IO_EPIPE;
369#endif
370#ifdef ERANGE
371 else if (errno == ERANGE) code = XML_IO_ERANGE;
372#endif
373#ifdef EROFS
374 else if (errno == EROFS) code = XML_IO_EROFS;
375#endif
376#ifdef ESPIPE
377 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
378#endif
379#ifdef ESRCH
380 else if (errno == ESRCH) code = XML_IO_ESRCH;
381#endif
382#ifdef ETIMEDOUT
383 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
384#endif
385#ifdef EXDEV
386 else if (errno == EXDEV) code = XML_IO_EXDEV;
387#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000388#ifdef ENOTSOCK
389 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
390#endif
391#ifdef EISCONN
392 else if (errno == EISCONN) code = XML_IO_EISCONN;
393#endif
394#ifdef ECONNREFUSED
395 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
396#endif
397#ifdef ETIMEDOUT
398 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
399#endif
400#ifdef ENETUNREACH
401 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
402#endif
403#ifdef EADDRINUSE
404 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
405#endif
406#ifdef EINPROGRESS
407 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
408#endif
409#ifdef EALREADY
410 else if (errno == EALREADY) code = XML_IO_EALREADY;
411#endif
412#ifdef EAFNOSUPPORT
413 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
414#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000415 else code = XML_IO_UNKNOWN;
416#endif /* HAVE_ERRNO_H */
417 }
418 idx = 0;
419 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
420 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
421
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000422 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
423}
424
425/**
426 * xmlIOErr:
427 * @code: the error number
428 * @extra: extra informations
429 *
430 * Handle an I/O error
431 */
432static void
433xmlIOErr(int code, const char *extra)
434{
435 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000436}
437
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000438/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000439 * __xmlLoaderErr:
440 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000441 * @extra: extra informations
442 *
443 * Handle a resource access error
444 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000445void
446__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000447{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000448 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000449 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000450 xmlGenericErrorFunc channel = NULL;
451 void *data = NULL;
452 xmlErrorLevel level = XML_ERR_ERROR;
453
Daniel Veillard157fee02003-10-31 10:36:03 +0000454 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
455 (ctxt->instate == XML_PARSER_EOF))
456 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000457 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
458 if (ctxt->validate) {
459 channel = ctxt->sax->error;
460 level = XML_ERR_ERROR;
461 } else {
462 channel = ctxt->sax->warning;
463 level = XML_ERR_WARNING;
464 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000465 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
466 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000467 data = ctxt->userData;
468 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000469 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000470 XML_IO_LOAD_ERROR, level, NULL, 0,
471 filename, NULL, NULL, 0, 0,
472 msg, filename);
473
474}
475
Daniel Veillard05d987b2003-10-08 11:54:57 +0000476/************************************************************************
477 * *
478 * Tree memory error handler *
479 * *
480 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000481/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000482 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000483 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000484 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000485 * This function is obsolete. Please see xmlURIFromPath in uri.c for
486 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000487 *
488 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000489 */
490xmlChar *
491xmlNormalizeWindowsPath(const xmlChar *path)
492{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000493 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000494}
495
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000496/**
497 * xmlCleanupInputCallbacks:
498 *
499 * clears the entire input callback table. this includes the
500 * compiled-in I/O.
501 */
502void
503xmlCleanupInputCallbacks(void)
504{
505 int i;
506
507 if (!xmlInputCallbackInitialized)
508 return;
509
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000510 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000511 xmlInputCallbackTable[i].matchcallback = NULL;
512 xmlInputCallbackTable[i].opencallback = NULL;
513 xmlInputCallbackTable[i].readcallback = NULL;
514 xmlInputCallbackTable[i].closecallback = NULL;
515 }
516
517 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000518 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000519}
520
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000521/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000522 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000523 *
524 * Clear the top input callback from the input stack. this includes the
525 * compiled-in I/O.
526 *
527 * Returns the number of input callback registered or -1 in case of error.
528 */
529int
530xmlPopInputCallbacks(void)
531{
532 if (!xmlInputCallbackInitialized)
533 return(-1);
534
535 if (xmlInputCallbackNr <= 0)
536 return(-1);
537
538 xmlInputCallbackNr--;
539 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
540 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
541 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
542 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
543
544 return(xmlInputCallbackNr);
545}
546
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000547#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000548/**
549 * xmlCleanupOutputCallbacks:
550 *
551 * clears the entire output callback table. this includes the
552 * compiled-in I/O callbacks.
553 */
554void
555xmlCleanupOutputCallbacks(void)
556{
557 int i;
558
559 if (!xmlOutputCallbackInitialized)
560 return;
561
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000562 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000563 xmlOutputCallbackTable[i].matchcallback = NULL;
564 xmlOutputCallbackTable[i].opencallback = NULL;
565 xmlOutputCallbackTable[i].writecallback = NULL;
566 xmlOutputCallbackTable[i].closecallback = NULL;
567 }
568
569 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000570 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000571}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000572#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000573
Owen Taylor3473f882001-02-23 17:55:21 +0000574/************************************************************************
575 * *
576 * Standard I/O for file accesses *
577 * *
578 ************************************************************************/
579
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000580#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
581
582/**
583 * xmlWrapOpenUtf8:
584 * @path: the path in utf-8 encoding
585 * @mode: type of access (0 - read, 1 - write)
586 *
587 * function opens the file specified by @path
588 *
589 */
590static FILE*
591xmlWrapOpenUtf8(const char *path,int mode)
592{
593 FILE *fd = NULL;
594 wchar_t *wPath;
595
596 wPath = __xmlIOWin32UTF8ToWChar(path);
597 if(wPath)
598 {
599 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
600 xmlFree(wPath);
601 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000602 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000603 if(fd == NULL)
604 fd = fopen(path, mode ? "wb" : "rb");
605
606 return fd;
607}
608
609/**
610 * xmlWrapStatUtf8:
611 * @path: the path in utf-8 encoding
612 * @info: structure that stores results
613 *
614 * function obtains information about the file or directory
615 *
616 */
617static int
618xmlWrapStatUtf8(const char *path,struct stat *info)
619{
620#ifdef HAVE_STAT
621 int retval = -1;
622 wchar_t *wPath;
623
624 wPath = __xmlIOWin32UTF8ToWChar(path);
625 if (wPath)
626 {
627 retval = _wstat(wPath,info);
628 xmlFree(wPath);
629 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000630 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000631 if(retval < 0)
632 retval = stat(path,info);
633 return retval;
634#else
635 return -1;
636#endif
637}
638
639/**
640 * xmlWrapOpenNative:
641 * @path: the path
642 * @mode: type of access (0 - read, 1 - write)
643 *
644 * function opens the file specified by @path
645 *
646 */
647static FILE*
648xmlWrapOpenNative(const char *path,int mode)
649{
650 return fopen(path,mode ? "wb" : "rb");
651}
652
653/**
654 * xmlWrapStatNative:
655 * @path: the path
656 * @info: structure that stores results
657 *
658 * function obtains information about the file or directory
659 *
660 */
661static int
662xmlWrapStatNative(const char *path,struct stat *info)
663{
664#ifdef HAVE_STAT
665 return stat(path,info);
666#else
667 return -1;
668#endif
669}
670
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000671typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
672static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
673typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
Rob Richards6460f922006-10-12 21:08:29 +0000674static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000675
676/**
677 * xmlInitPlatformSpecificIo:
678 *
679 * Initialize platform specific features.
680 */
681static void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000682xmlInitPlatformSpecificIo(void)
683{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000684 static int xmlPlatformIoInitialized = 0;
685 OSVERSIONINFO osvi;
686
687 if(xmlPlatformIoInitialized)
688 return;
689
690 osvi.dwOSVersionInfoSize = sizeof(osvi);
691
692 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
693 xmlWrapStat = xmlWrapStatUtf8;
694 xmlWrapOpen = xmlWrapOpenUtf8;
695 } else {
696 xmlWrapStat = xmlWrapStatNative;
697 xmlWrapOpen = xmlWrapOpenNative;
698 }
699
700 xmlPlatformIoInitialized = 1;
701 return;
702}
703
704#endif
705
Owen Taylor3473f882001-02-23 17:55:21 +0000706/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000707 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000708 * @path: the path to check
709 *
710 * function checks to see if @path is a valid source
711 * (file, socket...) for XML.
712 *
713 * if stat is not available on the target machine,
714 * returns 1. if stat fails, returns 0 (if calling
715 * stat on the filename fails, it can't be right).
716 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000717 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000718 */
719
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000720int
Owen Taylor3473f882001-02-23 17:55:21 +0000721xmlCheckFilename (const char *path)
722{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000723#ifdef HAVE_STAT
Daniel Veillard0b309952006-05-02 20:34:38 +0000724 struct stat stat_buffer;
725#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000726 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000727 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000728
Owen Taylor3473f882001-02-23 17:55:21 +0000729#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000730#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
731 if (xmlWrapStat(path, &stat_buffer) == -1)
732 return 0;
733#else
Owen Taylor3473f882001-02-23 17:55:21 +0000734 if (stat(path, &stat_buffer) == -1)
735 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000736#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000737#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000738 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000739 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000740#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000741#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000742 return 1;
743}
744
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000745static int
Owen Taylor3473f882001-02-23 17:55:21 +0000746xmlNop(void) {
747 return(0);
748}
749
750/**
Owen Taylor3473f882001-02-23 17:55:21 +0000751 * xmlFdRead:
752 * @context: the I/O context
753 * @buffer: where to drop data
754 * @len: number of bytes to read
755 *
756 * Read @len bytes to @buffer from the I/O channel.
757 *
758 * Returns the number of bytes written
759 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000760static int
Owen Taylor3473f882001-02-23 17:55:21 +0000761xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000762 int ret;
763
764 ret = read((int) (long) context, &buffer[0], len);
765 if (ret < 0) xmlIOErr(0, "read()");
766 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000767}
768
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000769#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000770/**
771 * xmlFdWrite:
772 * @context: the I/O context
773 * @buffer: where to get data
774 * @len: number of bytes to write
775 *
776 * Write @len bytes from @buffer to the I/O channel.
777 *
778 * Returns the number of bytes written
779 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000780static int
Owen Taylor3473f882001-02-23 17:55:21 +0000781xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000782 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000783
Daniel Veillard9b693b42005-10-28 14:54:17 +0000784 if (len > 0) {
785 ret = write((int) (long) context, &buffer[0], len);
786 if (ret < 0) xmlIOErr(0, "write()");
787 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000788 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000789}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000790#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000791
792/**
793 * xmlFdClose:
794 * @context: the I/O context
795 *
796 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000797 *
798 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000799 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000800static int
Owen Taylor3473f882001-02-23 17:55:21 +0000801xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000802 int ret;
803 ret = close((int) (long) context);
804 if (ret < 0) xmlIOErr(0, "close()");
805 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000806}
807
808/**
809 * xmlFileMatch:
810 * @filename: the URI for matching
811 *
812 * input from FILE *
813 *
814 * Returns 1 if matches, 0 otherwise
815 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000816int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000817xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000818 return(1);
819}
820
821/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000822 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000823 * @filename: the URI for matching
824 *
825 * input from FILE *, supports compressed input
826 * if @filename is " " then the standard input is used
827 *
828 * Returns an I/O context or NULL in case of error
829 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000830static void *
831xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000832 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000833 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000834
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000835 if (filename == NULL)
836 return(NULL);
837
Owen Taylor3473f882001-02-23 17:55:21 +0000838 if (!strcmp(filename, "-")) {
839 fd = stdin;
840 return((void *) fd);
841 }
842
Daniel Veillardf4862f02002-09-10 11:13:43 +0000843 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000844#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000845 path = &filename[17];
846#else
Owen Taylor3473f882001-02-23 17:55:21 +0000847 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000848#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000849 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000850#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000851 path = &filename[8];
852#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000853 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000854#endif
855 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000856 path = filename;
857
858 if (path == NULL)
859 return(NULL);
860 if (!xmlCheckFilename(path))
861 return(NULL);
862
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000863#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
864 fd = xmlWrapOpen(path, 0);
865#else
866 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000867#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000868 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000869 return((void *) fd);
870}
871
872/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000873 * xmlFileOpen:
874 * @filename: the URI for matching
875 *
876 * Wrapper around xmlFileOpen_real that try it with an unescaped
877 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000878 *
879 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000880 */
881void *
882xmlFileOpen (const char *filename) {
883 char *unescaped;
884 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000885
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000886 retval = xmlFileOpen_real(filename);
887 if (retval == NULL) {
888 unescaped = xmlURIUnescapeString(filename, 0, NULL);
889 if (unescaped != NULL) {
890 retval = xmlFileOpen_real(unescaped);
891 xmlFree(unescaped);
892 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000893 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000894
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000895 return retval;
896}
897
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000898#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000899/**
Owen Taylor3473f882001-02-23 17:55:21 +0000900 * xmlFileOpenW:
901 * @filename: the URI for matching
902 *
903 * output to from FILE *,
904 * if @filename is "-" then the standard output is used
905 *
906 * Returns an I/O context or NULL in case of error
907 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000908static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000909xmlFileOpenW (const char *filename) {
910 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000911 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000912
913 if (!strcmp(filename, "-")) {
914 fd = stdout;
915 return((void *) fd);
916 }
917
Daniel Veillardf4862f02002-09-10 11:13:43 +0000918 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000919#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000920 path = &filename[17];
921#else
Owen Taylor3473f882001-02-23 17:55:21 +0000922 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000923#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000924 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000925#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000926 path = &filename[8];
927#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000928 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000929#endif
930 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000931 path = filename;
932
933 if (path == NULL)
934 return(NULL);
935
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000936#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
937 fd = xmlWrapOpen(path, 1);
938#else
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000939 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000940#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000941
Daniel Veillardf7416012006-04-27 08:15:20 +0000942 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000943 return((void *) fd);
944}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000945#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000946
947/**
948 * xmlFileRead:
949 * @context: the I/O context
950 * @buffer: where to drop data
951 * @len: number of bytes to write
952 *
953 * Read @len bytes to @buffer from the I/O channel.
954 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000955 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000956 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000957int
Owen Taylor3473f882001-02-23 17:55:21 +0000958xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000959 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000960 if ((context == NULL) || (buffer == NULL))
961 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000962 ret = fread(&buffer[0], 1, len, (FILE *) context);
963 if (ret < 0) xmlIOErr(0, "fread()");
964 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000965}
966
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000967#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000968/**
969 * xmlFileWrite:
970 * @context: the I/O context
971 * @buffer: where to drop data
972 * @len: number of bytes to write
973 *
974 * Write @len bytes from @buffer to the I/O channel.
975 *
976 * Returns the number of bytes written
977 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000978static int
Owen Taylor3473f882001-02-23 17:55:21 +0000979xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000980 int items;
981
Daniel Veillardce682bc2004-11-05 17:22:25 +0000982 if ((context == NULL) || (buffer == NULL))
983 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000984 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000985 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000986 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000987 return(-1);
988 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000989 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000990}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000991#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000992
993/**
994 * xmlFileClose:
995 * @context: the I/O context
996 *
997 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000998 *
999 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001000 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001001int
Owen Taylor3473f882001-02-23 17:55:21 +00001002xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001003 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001004 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001005
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001006 if (context == NULL)
1007 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001008 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001009 if ((fil == stdout) || (fil == stderr)) {
1010 ret = fflush(fil);
1011 if (ret < 0)
1012 xmlIOErr(0, "fflush()");
1013 return(0);
1014 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001015 if (fil == stdin)
1016 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001017 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1018 if (ret < 0)
1019 xmlIOErr(0, "fclose()");
1020 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001021}
1022
1023/**
1024 * xmlFileFlush:
1025 * @context: the I/O context
1026 *
1027 * Flush an I/O channel
1028 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001029static int
Owen Taylor3473f882001-02-23 17:55:21 +00001030xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001031 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001032
1033 if (context == NULL)
1034 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001035 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1036 if (ret < 0)
1037 xmlIOErr(0, "fflush()");
1038 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001039}
1040
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001041#ifdef LIBXML_OUTPUT_ENABLED
1042/**
1043 * xmlBufferWrite:
1044 * @context: the xmlBuffer
1045 * @buffer: the data to write
1046 * @len: number of bytes to write
1047 *
1048 * Write @len bytes from @buffer to the xml buffer
1049 *
1050 * Returns the number of bytes written
1051 */
1052static int
1053xmlBufferWrite (void * context, const char * buffer, int len) {
1054 int ret;
1055
1056 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1057 if (ret != 0)
1058 return(-1);
1059 return(len);
1060}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001061#endif
1062
Owen Taylor3473f882001-02-23 17:55:21 +00001063#ifdef HAVE_ZLIB_H
1064/************************************************************************
1065 * *
1066 * I/O for compressed file accesses *
1067 * *
1068 ************************************************************************/
1069/**
1070 * xmlGzfileMatch:
1071 * @filename: the URI for matching
1072 *
1073 * input from compressed file test
1074 *
1075 * Returns 1 if matches, 0 otherwise
1076 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001077static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001078xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001079 return(1);
1080}
1081
1082/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001083 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001084 * @filename: the URI for matching
1085 *
1086 * input from compressed file open
1087 * if @filename is " " then the standard input is used
1088 *
1089 * Returns an I/O context or NULL in case of error
1090 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001091static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001092xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001093 const char *path = NULL;
1094 gzFile fd;
1095
1096 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001097 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001098 return((void *) fd);
1099 }
1100
Daniel Veillardf4862f02002-09-10 11:13:43 +00001101 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001102#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001103 path = &filename[17];
1104#else
Owen Taylor3473f882001-02-23 17:55:21 +00001105 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001106#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001107 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001108#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001109 path = &filename[8];
1110#else
Owen Taylor3473f882001-02-23 17:55:21 +00001111 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001112#endif
1113 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001114 path = filename;
1115
1116 if (path == NULL)
1117 return(NULL);
1118 if (!xmlCheckFilename(path))
1119 return(NULL);
1120
1121 fd = gzopen(path, "rb");
1122 return((void *) fd);
1123}
1124
1125/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001126 * xmlGzfileOpen:
1127 * @filename: the URI for matching
1128 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001129 * Wrapper around xmlGzfileOpen if the open fais, it will
1130 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001131 */
1132static void *
1133xmlGzfileOpen (const char *filename) {
1134 char *unescaped;
1135 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001136
1137 retval = xmlGzfileOpen_real(filename);
1138 if (retval == NULL) {
1139 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1140 if (unescaped != NULL) {
1141 retval = xmlGzfileOpen_real(unescaped);
1142 }
1143 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001144 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001145 return retval;
1146}
1147
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001148#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001149/**
Owen Taylor3473f882001-02-23 17:55:21 +00001150 * xmlGzfileOpenW:
1151 * @filename: the URI for matching
1152 * @compression: the compression factor (0 - 9 included)
1153 *
1154 * input from compressed file open
1155 * if @filename is " " then the standard input is used
1156 *
1157 * Returns an I/O context or NULL in case of error
1158 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001159static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001160xmlGzfileOpenW (const char *filename, int compression) {
1161 const char *path = NULL;
1162 char mode[15];
1163 gzFile fd;
1164
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001165 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001166 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001167 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001168 return((void *) fd);
1169 }
1170
Daniel Veillardf4862f02002-09-10 11:13:43 +00001171 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001172#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001173 path = &filename[17];
1174#else
Owen Taylor3473f882001-02-23 17:55:21 +00001175 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001176#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001177 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001178#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001179 path = &filename[8];
1180#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001181 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001182#endif
1183 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001184 path = filename;
1185
1186 if (path == NULL)
1187 return(NULL);
1188
1189 fd = gzopen(path, mode);
1190 return((void *) fd);
1191}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001192#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001193
1194/**
1195 * xmlGzfileRead:
1196 * @context: the I/O context
1197 * @buffer: where to drop data
1198 * @len: number of bytes to write
1199 *
1200 * Read @len bytes to @buffer from the compressed I/O channel.
1201 *
1202 * Returns the number of bytes written
1203 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001204static int
Owen Taylor3473f882001-02-23 17:55:21 +00001205xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001206 int ret;
1207
1208 ret = gzread((gzFile) context, &buffer[0], len);
1209 if (ret < 0) xmlIOErr(0, "gzread()");
1210 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001211}
1212
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001213#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001214/**
1215 * xmlGzfileWrite:
1216 * @context: the I/O context
1217 * @buffer: where to drop data
1218 * @len: number of bytes to write
1219 *
1220 * Write @len bytes from @buffer to the compressed I/O channel.
1221 *
1222 * Returns the number of bytes written
1223 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001224static int
Owen Taylor3473f882001-02-23 17:55:21 +00001225xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001226 int ret;
1227
1228 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1229 if (ret < 0) xmlIOErr(0, "gzwrite()");
1230 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001231}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001232#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001233
1234/**
1235 * xmlGzfileClose:
1236 * @context: the I/O context
1237 *
1238 * Close a compressed I/O channel
1239 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001240static int
Owen Taylor3473f882001-02-23 17:55:21 +00001241xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001242 int ret;
1243
1244 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1245 if (ret < 0) xmlIOErr(0, "gzclose()");
1246 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001247}
1248#endif /* HAVE_ZLIB_H */
1249
1250#ifdef LIBXML_HTTP_ENABLED
1251/************************************************************************
1252 * *
1253 * I/O for HTTP file accesses *
1254 * *
1255 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001256
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001257#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001258typedef struct xmlIOHTTPWriteCtxt_
1259{
1260 int compression;
1261
1262 char * uri;
1263
1264 void * doc_buff;
1265
1266} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1267
1268#ifdef HAVE_ZLIB_H
1269
1270#define DFLT_WBITS ( -15 )
1271#define DFLT_MEM_LVL ( 8 )
1272#define GZ_MAGIC1 ( 0x1f )
1273#define GZ_MAGIC2 ( 0x8b )
1274#define LXML_ZLIB_OS_CODE ( 0x03 )
1275#define INIT_HTTP_BUFF_SIZE ( 32768 )
1276#define DFLT_ZLIB_RATIO ( 5 )
1277
1278/*
1279** Data structure and functions to work with sending compressed data
1280** via HTTP.
1281*/
1282
1283typedef struct xmlZMemBuff_
1284{
1285 unsigned long size;
1286 unsigned long crc;
1287
1288 unsigned char * zbuff;
1289 z_stream zctrl;
1290
1291} xmlZMemBuff, *xmlZMemBuffPtr;
1292
1293/**
1294 * append_reverse_ulong
1295 * @buff: Compressed memory buffer
1296 * @data: Unsigned long to append
1297 *
1298 * Append a unsigned long in reverse byte order to the end of the
1299 * memory buffer.
1300 */
1301static void
1302append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1303
1304 int idx;
1305
1306 if ( buff == NULL )
1307 return;
1308
1309 /*
1310 ** This is plagiarized from putLong in gzio.c (zlib source) where
1311 ** the number "4" is hardcoded. If zlib is ever patched to
1312 ** support 64 bit file sizes, this code would need to be patched
1313 ** as well.
1314 */
1315
1316 for ( idx = 0; idx < 4; idx++ ) {
1317 *buff->zctrl.next_out = ( data & 0xff );
1318 data >>= 8;
1319 buff->zctrl.next_out++;
1320 }
1321
1322 return;
1323}
1324
1325/**
1326 *
1327 * xmlFreeZMemBuff
1328 * @buff: The memory buffer context to clear
1329 *
1330 * Release all the resources associated with the compressed memory buffer.
1331 */
1332static void
1333xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001334
1335#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001336 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001337#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001338
1339 if ( buff == NULL )
1340 return;
1341
1342 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001343#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001344 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001345 if ( z_err != Z_OK )
1346 xmlGenericError( xmlGenericErrorContext,
1347 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1348 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001349#else
1350 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001351#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001352
1353 xmlFree( buff );
1354 return;
1355}
1356
1357/**
1358 * xmlCreateZMemBuff
1359 *@compression: Compression value to use
1360 *
1361 * Create a memory buffer to hold the compressed XML document. The
1362 * compressed document in memory will end up being identical to what
1363 * would be created if gzopen/gzwrite/gzclose were being used to
1364 * write the document to disk. The code for the header/trailer data to
1365 * the compression is plagiarized from the zlib source files.
1366 */
1367static void *
1368xmlCreateZMemBuff( int compression ) {
1369
1370 int z_err;
1371 int hdr_lgth;
1372 xmlZMemBuffPtr buff = NULL;
1373
1374 if ( ( compression < 1 ) || ( compression > 9 ) )
1375 return ( NULL );
1376
1377 /* Create the control and data areas */
1378
1379 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1380 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001381 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001382 return ( NULL );
1383 }
1384
1385 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1386 buff->size = INIT_HTTP_BUFF_SIZE;
1387 buff->zbuff = xmlMalloc( buff->size );
1388 if ( buff->zbuff == NULL ) {
1389 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001390 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001391 return ( NULL );
1392 }
1393
1394 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1395 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1396 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001397 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001398 xmlFreeZMemBuff( buff );
1399 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001400 xmlStrPrintf(msg, 500,
1401 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1402 "Error initializing compression context. ZLIB error:",
1403 z_err );
1404 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001405 return ( NULL );
1406 }
1407
1408 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001409 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001410 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1411 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001412 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1413 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1414 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1415 buff->zctrl.avail_out = buff->size - hdr_lgth;
1416
1417 return ( buff );
1418}
1419
1420/**
1421 * xmlZMemBuffExtend
1422 * @buff: Buffer used to compress and consolidate data.
1423 * @ext_amt: Number of bytes to extend the buffer.
1424 *
1425 * Extend the internal buffer used to store the compressed data by the
1426 * specified amount.
1427 *
1428 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1429 * the original buffer still exists at the original size.
1430 */
1431static int
1432xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1433
1434 int rc = -1;
1435 size_t new_size;
1436 size_t cur_used;
1437
1438 unsigned char * tmp_ptr = NULL;
1439
1440 if ( buff == NULL )
1441 return ( -1 );
1442
1443 else if ( ext_amt == 0 )
1444 return ( 0 );
1445
1446 cur_used = buff->zctrl.next_out - buff->zbuff;
1447 new_size = buff->size + ext_amt;
1448
1449#ifdef DEBUG_HTTP
1450 if ( cur_used > new_size )
1451 xmlGenericError( xmlGenericErrorContext,
1452 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1453 "Buffer overwrite detected during compressed memory",
1454 "buffer extension. Overflowed by",
1455 (cur_used - new_size ) );
1456#endif
1457
1458 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1459 if ( tmp_ptr != NULL ) {
1460 rc = 0;
1461 buff->size = new_size;
1462 buff->zbuff = tmp_ptr;
1463 buff->zctrl.next_out = tmp_ptr + cur_used;
1464 buff->zctrl.avail_out = new_size - cur_used;
1465 }
1466 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001467 xmlChar msg[500];
1468 xmlStrPrintf(msg, 500,
1469 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1470 "Allocation failure extending output buffer to",
1471 new_size );
1472 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001473 }
1474
1475 return ( rc );
1476}
1477
1478/**
1479 * xmlZMemBuffAppend
1480 * @buff: Buffer used to compress and consolidate data
1481 * @src: Uncompressed source content to append to buffer
1482 * @len: Length of source data to append to buffer
1483 *
1484 * Compress and append data to the internal buffer. The data buffer
1485 * will be expanded if needed to store the additional data.
1486 *
1487 * Returns the number of bytes appended to the buffer or -1 on error.
1488 */
1489static int
1490xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1491
1492 int z_err;
1493 size_t min_accept;
1494
1495 if ( ( buff == NULL ) || ( src == NULL ) )
1496 return ( -1 );
1497
1498 buff->zctrl.avail_in = len;
1499 buff->zctrl.next_in = (unsigned char *)src;
1500 while ( buff->zctrl.avail_in > 0 ) {
1501 /*
1502 ** Extend the buffer prior to deflate call if a reasonable amount
1503 ** of output buffer space is not available.
1504 */
1505 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1506 if ( buff->zctrl.avail_out <= min_accept ) {
1507 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1508 return ( -1 );
1509 }
1510
1511 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1512 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001513 xmlChar msg[500];
1514 xmlStrPrintf(msg, 500,
1515 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001516 "Compression error while appending",
1517 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001518 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001519 return ( -1 );
1520 }
1521 }
1522
1523 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1524
1525 return ( len );
1526}
1527
1528/**
1529 * xmlZMemBuffGetContent
1530 * @buff: Compressed memory content buffer
1531 * @data_ref: Pointer reference to point to compressed content
1532 *
1533 * Flushes the compression buffers, appends gzip file trailers and
1534 * returns the compressed content and length of the compressed data.
1535 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1536 *
1537 * Returns the length of the compressed data or -1 on error.
1538 */
1539static int
1540xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1541
1542 int zlgth = -1;
1543 int z_err;
1544
1545 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1546 return ( -1 );
1547
1548 /* Need to loop until compression output buffers are flushed */
1549
1550 do
1551 {
1552 z_err = deflate( &buff->zctrl, Z_FINISH );
1553 if ( z_err == Z_OK ) {
1554 /* In this case Z_OK means more buffer space needed */
1555
1556 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1557 return ( -1 );
1558 }
1559 }
1560 while ( z_err == Z_OK );
1561
1562 /* If the compression state is not Z_STREAM_END, some error occurred */
1563
1564 if ( z_err == Z_STREAM_END ) {
1565
1566 /* Need to append the gzip data trailer */
1567
1568 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1569 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1570 return ( -1 );
1571 }
1572
1573 /*
1574 ** For whatever reason, the CRC and length data are pushed out
1575 ** in reverse byte order. So a memcpy can't be used here.
1576 */
1577
1578 append_reverse_ulong( buff, buff->crc );
1579 append_reverse_ulong( buff, buff->zctrl.total_in );
1580
1581 zlgth = buff->zctrl.next_out - buff->zbuff;
1582 *data_ref = (char *)buff->zbuff;
1583 }
1584
Daniel Veillard05d987b2003-10-08 11:54:57 +00001585 else {
1586 xmlChar msg[500];
1587 xmlStrPrintf(msg, 500,
1588 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1589 "Error flushing zlib buffers. Error code", z_err );
1590 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1591 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001592
1593 return ( zlgth );
1594}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001595#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001596#endif /* HAVE_ZLIB_H */
1597
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001598#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001599/**
1600 * xmlFreeHTTPWriteCtxt
1601 * @ctxt: Context to cleanup
1602 *
1603 * Free allocated memory and reclaim system resources.
1604 *
1605 * No return value.
1606 */
1607static void
1608xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1609{
1610 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001611 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001612
1613 if ( ctxt->doc_buff != NULL ) {
1614
1615#ifdef HAVE_ZLIB_H
1616 if ( ctxt->compression > 0 ) {
1617 xmlFreeZMemBuff( ctxt->doc_buff );
1618 }
1619 else
1620#endif
1621 {
1622 xmlOutputBufferClose( ctxt->doc_buff );
1623 }
1624 }
1625
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001626 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001627 return;
1628}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001629#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001630
1631
Owen Taylor3473f882001-02-23 17:55:21 +00001632/**
1633 * xmlIOHTTPMatch:
1634 * @filename: the URI for matching
1635 *
1636 * check if the URI matches an HTTP one
1637 *
1638 * Returns 1 if matches, 0 otherwise
1639 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001640int
Owen Taylor3473f882001-02-23 17:55:21 +00001641xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001642 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001643 return(1);
1644 return(0);
1645}
1646
1647/**
1648 * xmlIOHTTPOpen:
1649 * @filename: the URI for matching
1650 *
1651 * open an HTTP I/O channel
1652 *
1653 * Returns an I/O context or NULL in case of error
1654 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001655void *
Owen Taylor3473f882001-02-23 17:55:21 +00001656xmlIOHTTPOpen (const char *filename) {
1657 return(xmlNanoHTTPOpen(filename, NULL));
1658}
1659
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001660#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001661/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001662 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001663 * @post_uri: The destination URI for the document
1664 * @compression: The compression desired for the document.
1665 *
1666 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1667 * request. Non-static as is called from the output buffer creation routine.
1668 *
1669 * Returns an I/O context or NULL in case of error.
1670 */
1671
1672void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001673xmlIOHTTPOpenW(const char *post_uri, int compression)
1674{
Daniel Veillardf012a642001-07-23 19:10:52 +00001675
Daniel Veillard572577e2002-01-18 16:23:55 +00001676 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001677
Daniel Veillard572577e2002-01-18 16:23:55 +00001678 if (post_uri == NULL)
1679 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001680
Daniel Veillard572577e2002-01-18 16:23:55 +00001681 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1682 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001683 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001684 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001685 }
1686
Daniel Veillard572577e2002-01-18 16:23:55 +00001687 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001688
Daniel Veillard572577e2002-01-18 16:23:55 +00001689 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1690 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001691 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001692 xmlFreeHTTPWriteCtxt(ctxt);
1693 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001694 }
1695
1696 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001697 * ** Since the document length is required for an HTTP post,
1698 * ** need to put the document into a buffer. A memory buffer
1699 * ** is being used to avoid pushing the data to disk and back.
1700 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001701
1702#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001703 if ((compression > 0) && (compression <= 9)) {
1704
1705 ctxt->compression = compression;
1706 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1707 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001708#endif
1709 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001710 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001711
Daniel Veillard572577e2002-01-18 16:23:55 +00001712 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001713 }
1714
Daniel Veillard572577e2002-01-18 16:23:55 +00001715 if (ctxt->doc_buff == NULL) {
1716 xmlFreeHTTPWriteCtxt(ctxt);
1717 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001718 }
1719
Daniel Veillard572577e2002-01-18 16:23:55 +00001720 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001721}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001722#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001723
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001724#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001725/**
1726 * xmlIOHTTPDfltOpenW
1727 * @post_uri: The destination URI for this document.
1728 *
1729 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1730 * HTTP post command. This function should generally not be used as
1731 * the open callback is short circuited in xmlOutputBufferCreateFile.
1732 *
1733 * Returns a pointer to the new IO context.
1734 */
1735static void *
1736xmlIOHTTPDfltOpenW( const char * post_uri ) {
1737 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1738}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001739#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001740
1741/**
Owen Taylor3473f882001-02-23 17:55:21 +00001742 * xmlIOHTTPRead:
1743 * @context: the I/O context
1744 * @buffer: where to drop data
1745 * @len: number of bytes to write
1746 *
1747 * Read @len bytes to @buffer from the I/O channel.
1748 *
1749 * Returns the number of bytes written
1750 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001751int
Owen Taylor3473f882001-02-23 17:55:21 +00001752xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001753 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001754 return(xmlNanoHTTPRead(context, &buffer[0], len));
1755}
1756
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001757#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001758/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001759 * xmlIOHTTPWrite
1760 * @context: previously opened writing context
1761 * @buffer: data to output to temporary buffer
1762 * @len: bytes to output
1763 *
1764 * Collect data from memory buffer into a temporary file for later
1765 * processing.
1766 *
1767 * Returns number of bytes written.
1768 */
1769
1770static int
1771xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1772
1773 xmlIOHTTPWriteCtxtPtr ctxt = context;
1774
1775 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1776 return ( -1 );
1777
1778 if ( len > 0 ) {
1779
1780 /* Use gzwrite or fwrite as previously setup in the open call */
1781
1782#ifdef HAVE_ZLIB_H
1783 if ( ctxt->compression > 0 )
1784 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1785
1786 else
1787#endif
1788 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1789
1790 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001791 xmlChar msg[500];
1792 xmlStrPrintf(msg, 500,
1793 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001794 "Error appending to internal buffer.",
1795 "Error sending document to URI",
1796 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001797 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001798 }
1799 }
1800
1801 return ( len );
1802}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001803#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001804
1805
1806/**
Owen Taylor3473f882001-02-23 17:55:21 +00001807 * xmlIOHTTPClose:
1808 * @context: the I/O context
1809 *
1810 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001811 *
1812 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001813 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001814int
Owen Taylor3473f882001-02-23 17:55:21 +00001815xmlIOHTTPClose (void * context) {
1816 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001817 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001818}
Daniel Veillardf012a642001-07-23 19:10:52 +00001819
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001820#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001821/**
1822 * xmlIOHTTCloseWrite
1823 * @context: The I/O context
1824 * @http_mthd: The HTTP method to be used when sending the data
1825 *
1826 * Close the transmit HTTP I/O channel and actually send the data.
1827 */
1828static int
1829xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1830
1831 int close_rc = -1;
1832 int http_rtn = 0;
1833 int content_lgth = 0;
1834 xmlIOHTTPWriteCtxtPtr ctxt = context;
1835
1836 char * http_content = NULL;
1837 char * content_encoding = NULL;
1838 char * content_type = (char *) "text/xml";
1839 void * http_ctxt = NULL;
1840
1841 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1842 return ( -1 );
1843
1844 /* Retrieve the content from the appropriate buffer */
1845
1846#ifdef HAVE_ZLIB_H
1847
1848 if ( ctxt->compression > 0 ) {
1849 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1850 content_encoding = (char *) "Content-Encoding: gzip";
1851 }
1852 else
1853#endif
1854 {
1855 /* Pull the data out of the memory output buffer */
1856
1857 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1858 http_content = (char *)dctxt->buffer->content;
1859 content_lgth = dctxt->buffer->use;
1860 }
1861
1862 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001863 xmlChar msg[500];
1864 xmlStrPrintf(msg, 500,
1865 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1866 "Error retrieving content.\nUnable to",
1867 http_mthd, "data to URI", ctxt->uri );
1868 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001869 }
1870
1871 else {
1872
1873 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1874 &content_type, content_encoding,
1875 content_lgth );
1876
1877 if ( http_ctxt != NULL ) {
1878#ifdef DEBUG_HTTP
1879 /* If testing/debugging - dump reply with request content */
1880
1881 FILE * tst_file = NULL;
1882 char buffer[ 4096 ];
1883 char * dump_name = NULL;
1884 int avail;
1885
1886 xmlGenericError( xmlGenericErrorContext,
1887 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1888 http_mthd, ctxt->uri,
1889 xmlNanoHTTPReturnCode( http_ctxt ) );
1890
1891 /*
1892 ** Since either content or reply may be gzipped,
1893 ** dump them to separate files instead of the
1894 ** standard error context.
1895 */
1896
1897 dump_name = tempnam( NULL, "lxml" );
1898 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001899 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001900
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001901 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001902 if ( tst_file != NULL ) {
1903 xmlGenericError( xmlGenericErrorContext,
1904 "Transmitted content saved in file: %s\n", buffer );
1905
1906 fwrite( http_content, sizeof( char ),
1907 content_lgth, tst_file );
1908 fclose( tst_file );
1909 }
1910
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001911 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001912 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001913 if ( tst_file != NULL ) {
1914 xmlGenericError( xmlGenericErrorContext,
1915 "Reply content saved in file: %s\n", buffer );
1916
1917
1918 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1919 buffer, sizeof( buffer ) )) > 0 ) {
1920
1921 fwrite( buffer, sizeof( char ), avail, tst_file );
1922 }
1923
1924 fclose( tst_file );
1925 }
1926
1927 free( dump_name );
1928 }
1929#endif /* DEBUG_HTTP */
1930
1931 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1932 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1933 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001934 else {
1935 xmlChar msg[500];
1936 xmlStrPrintf(msg, 500,
1937 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001938 http_mthd, content_lgth,
1939 "bytes to URI", ctxt->uri,
1940 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001941 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1942 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001943
1944 xmlNanoHTTPClose( http_ctxt );
1945 xmlFree( content_type );
1946 }
1947 }
1948
1949 /* Final cleanups */
1950
1951 xmlFreeHTTPWriteCtxt( ctxt );
1952
1953 return ( close_rc );
1954}
1955
1956/**
1957 * xmlIOHTTPClosePut
1958 *
1959 * @context: The I/O context
1960 *
1961 * Close the transmit HTTP I/O channel and actually send data using a PUT
1962 * HTTP method.
1963 */
1964static int
1965xmlIOHTTPClosePut( void * ctxt ) {
1966 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1967}
1968
1969
1970/**
1971 * xmlIOHTTPClosePost
1972 *
1973 * @context: The I/O context
1974 *
1975 * Close the transmit HTTP I/O channel and actually send data using a POST
1976 * HTTP method.
1977 */
1978static int
1979xmlIOHTTPClosePost( void * ctxt ) {
1980 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1981}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001982#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001983
Owen Taylor3473f882001-02-23 17:55:21 +00001984#endif /* LIBXML_HTTP_ENABLED */
1985
1986#ifdef LIBXML_FTP_ENABLED
1987/************************************************************************
1988 * *
1989 * I/O for FTP file accesses *
1990 * *
1991 ************************************************************************/
1992/**
1993 * xmlIOFTPMatch:
1994 * @filename: the URI for matching
1995 *
1996 * check if the URI matches an FTP one
1997 *
1998 * Returns 1 if matches, 0 otherwise
1999 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002000int
Owen Taylor3473f882001-02-23 17:55:21 +00002001xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002002 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002003 return(1);
2004 return(0);
2005}
2006
2007/**
2008 * xmlIOFTPOpen:
2009 * @filename: the URI for matching
2010 *
2011 * open an FTP I/O channel
2012 *
2013 * Returns an I/O context or NULL in case of error
2014 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002015void *
Owen Taylor3473f882001-02-23 17:55:21 +00002016xmlIOFTPOpen (const char *filename) {
2017 return(xmlNanoFTPOpen(filename));
2018}
2019
2020/**
2021 * xmlIOFTPRead:
2022 * @context: the I/O context
2023 * @buffer: where to drop data
2024 * @len: number of bytes to write
2025 *
2026 * Read @len bytes to @buffer from the I/O channel.
2027 *
2028 * Returns the number of bytes written
2029 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002030int
Owen Taylor3473f882001-02-23 17:55:21 +00002031xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002032 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002033 return(xmlNanoFTPRead(context, &buffer[0], len));
2034}
2035
2036/**
2037 * xmlIOFTPClose:
2038 * @context: the I/O context
2039 *
2040 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002041 *
2042 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002043 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002044int
Owen Taylor3473f882001-02-23 17:55:21 +00002045xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002046 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002047}
2048#endif /* LIBXML_FTP_ENABLED */
2049
2050
2051/**
2052 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002053 * @matchFunc: the xmlInputMatchCallback
2054 * @openFunc: the xmlInputOpenCallback
2055 * @readFunc: the xmlInputReadCallback
2056 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002057 *
2058 * Register a new set of I/O callback for handling parser input.
2059 *
2060 * Returns the registered handler number or -1 in case of error
2061 */
2062int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002063xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2064 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2065 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002066 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2067 return(-1);
2068 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002069 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2070 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2071 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2072 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002073 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002074 return(xmlInputCallbackNr++);
2075}
2076
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002077#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002078/**
2079 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002080 * @matchFunc: the xmlOutputMatchCallback
2081 * @openFunc: the xmlOutputOpenCallback
2082 * @writeFunc: the xmlOutputWriteCallback
2083 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002084 *
2085 * Register a new set of I/O callback for handling output.
2086 *
2087 * Returns the registered handler number or -1 in case of error
2088 */
2089int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002090xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2091 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2092 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002093 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
2094 return(-1);
2095 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002096 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2097 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2098 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2099 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002100 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002101 return(xmlOutputCallbackNr++);
2102}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002103#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002104
2105/**
2106 * xmlRegisterDefaultInputCallbacks:
2107 *
2108 * Registers the default compiled-in I/O handlers.
2109 */
2110void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002111xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002112 if (xmlInputCallbackInitialized)
2113 return;
2114
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002115#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2116 xmlInitPlatformSpecificIo();
2117#endif
2118
Owen Taylor3473f882001-02-23 17:55:21 +00002119 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2120 xmlFileRead, xmlFileClose);
2121#ifdef HAVE_ZLIB_H
2122 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2123 xmlGzfileRead, xmlGzfileClose);
2124#endif /* HAVE_ZLIB_H */
2125
2126#ifdef LIBXML_HTTP_ENABLED
2127 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2128 xmlIOHTTPRead, xmlIOHTTPClose);
2129#endif /* LIBXML_HTTP_ENABLED */
2130
2131#ifdef LIBXML_FTP_ENABLED
2132 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2133 xmlIOFTPRead, xmlIOFTPClose);
2134#endif /* LIBXML_FTP_ENABLED */
2135 xmlInputCallbackInitialized = 1;
2136}
2137
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002138#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002139/**
2140 * xmlRegisterDefaultOutputCallbacks:
2141 *
2142 * Registers the default compiled-in I/O handlers.
2143 */
2144void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002145xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002146 if (xmlOutputCallbackInitialized)
2147 return;
2148
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002149#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2150 xmlInitPlatformSpecificIo();
2151#endif
2152
Owen Taylor3473f882001-02-23 17:55:21 +00002153 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2154 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002155
2156#ifdef LIBXML_HTTP_ENABLED
2157 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2158 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2159#endif
2160
Owen Taylor3473f882001-02-23 17:55:21 +00002161/*********************************
2162 No way a-priori to distinguish between gzipped files from
2163 uncompressed ones except opening if existing then closing
2164 and saving with same compression ratio ... a pain.
2165
2166#ifdef HAVE_ZLIB_H
2167 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2168 xmlGzfileWrite, xmlGzfileClose);
2169#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002170
2171 Nor FTP PUT ....
2172#ifdef LIBXML_FTP_ENABLED
2173 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2174 xmlIOFTPWrite, xmlIOFTPClose);
2175#endif
2176 **********************************/
2177 xmlOutputCallbackInitialized = 1;
2178}
2179
Daniel Veillardf012a642001-07-23 19:10:52 +00002180#ifdef LIBXML_HTTP_ENABLED
2181/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002182 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002183 *
2184 * By default, libxml submits HTTP output requests using the "PUT" method.
2185 * Calling this method changes the HTTP output method to use the "POST"
2186 * method instead.
2187 *
2188 */
2189void
2190xmlRegisterHTTPPostCallbacks( void ) {
2191
2192 /* Register defaults if not done previously */
2193
2194 if ( xmlOutputCallbackInitialized == 0 )
2195 xmlRegisterDefaultOutputCallbacks( );
2196
2197 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2198 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2199 return;
2200}
2201#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002202#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002203
Owen Taylor3473f882001-02-23 17:55:21 +00002204/**
2205 * xmlAllocParserInputBuffer:
2206 * @enc: the charset encoding if known
2207 *
2208 * Create a buffered parser input for progressive parsing
2209 *
2210 * Returns the new parser input or NULL
2211 */
2212xmlParserInputBufferPtr
2213xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2214 xmlParserInputBufferPtr ret;
2215
2216 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2217 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002218 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002219 return(NULL);
2220 }
2221 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002222 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002223 if (ret->buffer == NULL) {
2224 xmlFree(ret);
2225 return(NULL);
2226 }
2227 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2228 ret->encoder = xmlGetCharEncodingHandler(enc);
2229 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002230 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002231 else
2232 ret->raw = NULL;
2233 ret->readcallback = NULL;
2234 ret->closecallback = NULL;
2235 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002236 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002237 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002238
2239 return(ret);
2240}
2241
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002242#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002243/**
2244 * xmlAllocOutputBuffer:
2245 * @encoder: the encoding converter or NULL
2246 *
2247 * Create a buffered parser output
2248 *
2249 * Returns the new parser output or NULL
2250 */
2251xmlOutputBufferPtr
2252xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2253 xmlOutputBufferPtr ret;
2254
2255 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2256 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002257 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002258 return(NULL);
2259 }
2260 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2261 ret->buffer = xmlBufferCreate();
2262 if (ret->buffer == NULL) {
2263 xmlFree(ret);
2264 return(NULL);
2265 }
2266 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2267 ret->encoder = encoder;
2268 if (encoder != NULL) {
2269 ret->conv = xmlBufferCreateSize(4000);
2270 /*
2271 * This call is designed to initiate the encoder state
2272 */
2273 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2274 } else
2275 ret->conv = NULL;
2276 ret->writecallback = NULL;
2277 ret->closecallback = NULL;
2278 ret->context = NULL;
2279 ret->written = 0;
2280
2281 return(ret);
2282}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002283#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002284
2285/**
2286 * xmlFreeParserInputBuffer:
2287 * @in: a buffered parser input
2288 *
2289 * Free up the memory used by a buffered parser input
2290 */
2291void
2292xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002293 if (in == NULL) return;
2294
Owen Taylor3473f882001-02-23 17:55:21 +00002295 if (in->raw) {
2296 xmlBufferFree(in->raw);
2297 in->raw = NULL;
2298 }
2299 if (in->encoder != NULL) {
2300 xmlCharEncCloseFunc(in->encoder);
2301 }
2302 if (in->closecallback != NULL) {
2303 in->closecallback(in->context);
2304 }
2305 if (in->buffer != NULL) {
2306 xmlBufferFree(in->buffer);
2307 in->buffer = NULL;
2308 }
2309
Owen Taylor3473f882001-02-23 17:55:21 +00002310 xmlFree(in);
2311}
2312
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002313#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002314/**
2315 * xmlOutputBufferClose:
2316 * @out: a buffered output
2317 *
2318 * flushes and close the output I/O channel
2319 * and free up all the associated resources
2320 *
2321 * Returns the number of byte written or -1 in case of error.
2322 */
2323int
Daniel Veillard828ce832003-10-08 19:19:10 +00002324xmlOutputBufferClose(xmlOutputBufferPtr out)
2325{
Owen Taylor3473f882001-02-23 17:55:21 +00002326 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002327 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002328
2329 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002330 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002331 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002332 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002333 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002334 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002335 }
2336 written = out->written;
2337 if (out->conv) {
2338 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002339 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002340 }
2341 if (out->encoder != NULL) {
2342 xmlCharEncCloseFunc(out->encoder);
2343 }
2344 if (out->buffer != NULL) {
2345 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002346 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002347 }
2348
Daniel Veillard828ce832003-10-08 19:19:10 +00002349 if (out->error)
2350 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002351 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002352 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002353}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002354#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002355
Daniel Veillard1b243b42004-06-08 10:16:42 +00002356xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002357__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002358 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002359 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002360 void *context = NULL;
2361
2362 if (xmlInputCallbackInitialized == 0)
2363 xmlRegisterDefaultInputCallbacks();
2364
2365 if (URI == NULL) return(NULL);
2366
2367 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002368 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002369 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002370 */
2371 if (context == NULL) {
2372 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2373 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2374 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002375 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002376 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002377 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002378 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002379 }
Owen Taylor3473f882001-02-23 17:55:21 +00002380 }
2381 }
2382 if (context == NULL) {
2383 return(NULL);
2384 }
2385
2386 /*
2387 * Allocate the Input buffer front-end.
2388 */
2389 ret = xmlAllocParserInputBuffer(enc);
2390 if (ret != NULL) {
2391 ret->context = context;
2392 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2393 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002394#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002395 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2396 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002397 if (((z_stream *)context)->avail_in > 4) {
2398 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002399 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002400 if (gzread(context, buff4, 4) == 4) {
2401 if (strncmp(buff4, cptr, 4) == 0)
2402 ret->compressed = 0;
2403 else
2404 ret->compressed = 1;
2405 gzrewind(context);
2406 }
2407 }
2408 }
2409#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002410 }
William M. Brack42331a92004-07-29 07:07:16 +00002411 else
2412 xmlInputCallbackTable[i].closecallback (context);
2413
Owen Taylor3473f882001-02-23 17:55:21 +00002414 return(ret);
2415}
2416
2417/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002418 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002419 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002420 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002421 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002422 * Create a buffered parser input for the progressive parsing of a file
2423 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002424 * Automatic support for ZLIB/Compress compressed document is provided
2425 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002426 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002427 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002428 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002429 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002430xmlParserInputBufferPtr
2431xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2432 if ((xmlParserInputBufferCreateFilenameValue)) {
2433 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2434 }
2435 return __xmlParserInputBufferCreateFilename(URI, enc);
2436}
2437
2438#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002439xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002440__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002441 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002442 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002443 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002444 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002445 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002446 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002447 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002448#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002449 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002450#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002451
Owen Taylor3473f882001-02-23 17:55:21 +00002452 if (xmlOutputCallbackInitialized == 0)
2453 xmlRegisterDefaultOutputCallbacks();
2454
2455 if (URI == NULL) return(NULL);
2456
Daniel Veillard966a31e2004-05-09 02:58:44 +00002457 puri = xmlParseURI(URI);
2458 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002459#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002460 if ((puri->scheme != NULL) &&
2461 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002462 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002463#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002464 /*
2465 * try to limit the damages of the URI unescaping code.
2466 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002467 if ((puri->scheme == NULL) ||
2468 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002469 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2470 xmlFreeURI(puri);
2471 }
Owen Taylor3473f882001-02-23 17:55:21 +00002472
2473 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002474 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002475 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002476 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002477 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002478 if (unescaped != NULL) {
2479#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002480 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002481 context = xmlGzfileOpenW(unescaped, compression);
2482 if (context != NULL) {
2483 ret = xmlAllocOutputBuffer(encoder);
2484 if (ret != NULL) {
2485 ret->context = context;
2486 ret->writecallback = xmlGzfileWrite;
2487 ret->closecallback = xmlGzfileClose;
2488 }
2489 xmlFree(unescaped);
2490 return(ret);
2491 }
2492 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002493#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002494 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2495 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2496 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2497#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2498 /* Need to pass compression parameter into HTTP open calls */
2499 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2500 context = xmlIOHTTPOpenW(unescaped, compression);
2501 else
2502#endif
2503 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2504 if (context != NULL)
2505 break;
2506 }
2507 }
2508 xmlFree(unescaped);
2509 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002510
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002511 /*
2512 * If this failed try with a non-escaped URI this may be a strange
2513 * filename
2514 */
2515 if (context == NULL) {
2516#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002517 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002518 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002519 if (context != NULL) {
2520 ret = xmlAllocOutputBuffer(encoder);
2521 if (ret != NULL) {
2522 ret->context = context;
2523 ret->writecallback = xmlGzfileWrite;
2524 ret->closecallback = xmlGzfileClose;
2525 }
2526 return(ret);
2527 }
2528 }
2529#endif
2530 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2531 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002532 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002533#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2534 /* Need to pass compression parameter into HTTP open calls */
2535 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2536 context = xmlIOHTTPOpenW(URI, compression);
2537 else
2538#endif
2539 context = xmlOutputCallbackTable[i].opencallback(URI);
2540 if (context != NULL)
2541 break;
2542 }
Owen Taylor3473f882001-02-23 17:55:21 +00002543 }
2544 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002545
Owen Taylor3473f882001-02-23 17:55:21 +00002546 if (context == NULL) {
2547 return(NULL);
2548 }
2549
2550 /*
2551 * Allocate the Output buffer front-end.
2552 */
2553 ret = xmlAllocOutputBuffer(encoder);
2554 if (ret != NULL) {
2555 ret->context = context;
2556 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2557 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2558 }
2559 return(ret);
2560}
Daniel Veillard0335a842004-06-02 16:18:40 +00002561
2562/**
2563 * xmlOutputBufferCreateFilename:
2564 * @URI: a C string containing the URI or filename
2565 * @encoder: the encoding converter or NULL
2566 * @compression: the compression ration (0 none, 9 max).
2567 *
2568 * Create a buffered output for the progressive saving of a file
2569 * If filename is "-' then we use stdout as the output.
2570 * Automatic support for ZLIB/Compress compressed document is provided
2571 * by default if found at compile-time.
2572 * TODO: currently if compression is set, the library only support
2573 * writing to a local file.
2574 *
2575 * Returns the new output or NULL
2576 */
2577xmlOutputBufferPtr
2578xmlOutputBufferCreateFilename(const char *URI,
2579 xmlCharEncodingHandlerPtr encoder,
2580 int compression ATTRIBUTE_UNUSED) {
2581 if ((xmlOutputBufferCreateFilenameValue)) {
2582 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2583 }
2584 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2585}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002586#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002587
2588/**
2589 * xmlParserInputBufferCreateFile:
2590 * @file: a FILE*
2591 * @enc: the charset encoding if known
2592 *
2593 * Create a buffered parser input for the progressive parsing of a FILE *
2594 * buffered C I/O
2595 *
2596 * Returns the new parser input or NULL
2597 */
2598xmlParserInputBufferPtr
2599xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2600 xmlParserInputBufferPtr ret;
2601
2602 if (xmlInputCallbackInitialized == 0)
2603 xmlRegisterDefaultInputCallbacks();
2604
2605 if (file == NULL) return(NULL);
2606
2607 ret = xmlAllocParserInputBuffer(enc);
2608 if (ret != NULL) {
2609 ret->context = file;
2610 ret->readcallback = xmlFileRead;
2611 ret->closecallback = xmlFileFlush;
2612 }
2613
2614 return(ret);
2615}
2616
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002617#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002618/**
2619 * xmlOutputBufferCreateFile:
2620 * @file: a FILE*
2621 * @encoder: the encoding converter or NULL
2622 *
2623 * Create a buffered output for the progressive saving to a FILE *
2624 * buffered C I/O
2625 *
2626 * Returns the new parser output or NULL
2627 */
2628xmlOutputBufferPtr
2629xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2630 xmlOutputBufferPtr ret;
2631
2632 if (xmlOutputCallbackInitialized == 0)
2633 xmlRegisterDefaultOutputCallbacks();
2634
2635 if (file == NULL) return(NULL);
2636
2637 ret = xmlAllocOutputBuffer(encoder);
2638 if (ret != NULL) {
2639 ret->context = file;
2640 ret->writecallback = xmlFileWrite;
2641 ret->closecallback = xmlFileFlush;
2642 }
2643
2644 return(ret);
2645}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002646
2647/**
2648 * xmlOutputBufferCreateBuffer:
2649 * @buffer: a xmlBufferPtr
2650 * @encoder: the encoding converter or NULL
2651 *
2652 * Create a buffered output for the progressive saving to a xmlBuffer
2653 *
2654 * Returns the new parser output or NULL
2655 */
2656xmlOutputBufferPtr
2657xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2658 xmlCharEncodingHandlerPtr encoder) {
2659 xmlOutputBufferPtr ret;
2660
2661 if (buffer == NULL) return(NULL);
2662
Rob Richardsa44f2342005-11-09 18:03:45 +00002663 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2664 xmlBufferWrite,
2665 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002666 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002667
2668 return(ret);
2669}
2670
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002671#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002672
2673/**
2674 * xmlParserInputBufferCreateFd:
2675 * @fd: a file descriptor number
2676 * @enc: the charset encoding if known
2677 *
2678 * Create a buffered parser input for the progressive parsing for the input
2679 * from a file descriptor
2680 *
2681 * Returns the new parser input or NULL
2682 */
2683xmlParserInputBufferPtr
2684xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2685 xmlParserInputBufferPtr ret;
2686
2687 if (fd < 0) return(NULL);
2688
2689 ret = xmlAllocParserInputBuffer(enc);
2690 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002691 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002692 ret->readcallback = xmlFdRead;
2693 ret->closecallback = xmlFdClose;
2694 }
2695
2696 return(ret);
2697}
2698
2699/**
2700 * xmlParserInputBufferCreateMem:
2701 * @mem: the memory input
2702 * @size: the length of the memory block
2703 * @enc: the charset encoding if known
2704 *
2705 * Create a buffered parser input for the progressive parsing for the input
2706 * from a memory area.
2707 *
2708 * Returns the new parser input or NULL
2709 */
2710xmlParserInputBufferPtr
2711xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2712 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002713 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002714
2715 if (size <= 0) return(NULL);
2716 if (mem == NULL) return(NULL);
2717
2718 ret = xmlAllocParserInputBuffer(enc);
2719 if (ret != NULL) {
2720 ret->context = (void *) mem;
2721 ret->readcallback = (xmlInputReadCallback) xmlNop;
2722 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002723 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2724 if (errcode != 0) {
2725 xmlFree(ret);
2726 return(NULL);
2727 }
Owen Taylor3473f882001-02-23 17:55:21 +00002728 }
2729
2730 return(ret);
2731}
2732
2733/**
Daniel Veillard53350552003-09-18 13:35:51 +00002734 * xmlParserInputBufferCreateStatic:
2735 * @mem: the memory input
2736 * @size: the length of the memory block
2737 * @enc: the charset encoding if known
2738 *
2739 * Create a buffered parser input for the progressive parsing for the input
2740 * from an immutable memory area. This will not copy the memory area to
2741 * the buffer, but the memory is expected to be available until the end of
2742 * the parsing, this is useful for example when using mmap'ed file.
2743 *
2744 * Returns the new parser input or NULL
2745 */
2746xmlParserInputBufferPtr
2747xmlParserInputBufferCreateStatic(const char *mem, int size,
2748 xmlCharEncoding enc) {
2749 xmlParserInputBufferPtr ret;
2750
2751 if (size <= 0) return(NULL);
2752 if (mem == NULL) return(NULL);
2753
2754 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2755 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002756 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002757 return(NULL);
2758 }
2759 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002760 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002761 if (ret->buffer == NULL) {
2762 xmlFree(ret);
2763 return(NULL);
2764 }
2765 ret->encoder = xmlGetCharEncodingHandler(enc);
2766 if (ret->encoder != NULL)
2767 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2768 else
2769 ret->raw = NULL;
2770 ret->compressed = -1;
2771 ret->context = (void *) mem;
2772 ret->readcallback = NULL;
2773 ret->closecallback = NULL;
2774
2775 return(ret);
2776}
2777
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002778#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002779/**
Owen Taylor3473f882001-02-23 17:55:21 +00002780 * xmlOutputBufferCreateFd:
2781 * @fd: a file descriptor number
2782 * @encoder: the encoding converter or NULL
2783 *
2784 * Create a buffered output for the progressive saving
2785 * to a file descriptor
2786 *
2787 * Returns the new parser output or NULL
2788 */
2789xmlOutputBufferPtr
2790xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2791 xmlOutputBufferPtr ret;
2792
2793 if (fd < 0) return(NULL);
2794
2795 ret = xmlAllocOutputBuffer(encoder);
2796 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002797 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002798 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002799 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002800 }
2801
2802 return(ret);
2803}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002804#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002805
2806/**
2807 * xmlParserInputBufferCreateIO:
2808 * @ioread: an I/O read function
2809 * @ioclose: an I/O close function
2810 * @ioctx: an I/O handler
2811 * @enc: the charset encoding if known
2812 *
2813 * Create a buffered parser input for the progressive parsing for the input
2814 * from an I/O handler
2815 *
2816 * Returns the new parser input or NULL
2817 */
2818xmlParserInputBufferPtr
2819xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2820 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2821 xmlParserInputBufferPtr ret;
2822
2823 if (ioread == NULL) return(NULL);
2824
2825 ret = xmlAllocParserInputBuffer(enc);
2826 if (ret != NULL) {
2827 ret->context = (void *) ioctx;
2828 ret->readcallback = ioread;
2829 ret->closecallback = ioclose;
2830 }
2831
2832 return(ret);
2833}
2834
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002835#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002836/**
2837 * xmlOutputBufferCreateIO:
2838 * @iowrite: an I/O write function
2839 * @ioclose: an I/O close function
2840 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002841 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002842 *
2843 * Create a buffered output for the progressive saving
2844 * to an I/O handler
2845 *
2846 * Returns the new parser output or NULL
2847 */
2848xmlOutputBufferPtr
2849xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2850 xmlOutputCloseCallback ioclose, void *ioctx,
2851 xmlCharEncodingHandlerPtr encoder) {
2852 xmlOutputBufferPtr ret;
2853
2854 if (iowrite == NULL) return(NULL);
2855
2856 ret = xmlAllocOutputBuffer(encoder);
2857 if (ret != NULL) {
2858 ret->context = (void *) ioctx;
2859 ret->writecallback = iowrite;
2860 ret->closecallback = ioclose;
2861 }
2862
2863 return(ret);
2864}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002865#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002866
2867/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002868 * xmlParserInputBufferCreateFilenameDefault:
2869 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2870 *
2871 * Registers a callback for URI input file handling
2872 *
2873 * Returns the old value of the registration function
2874 */
2875xmlParserInputBufferCreateFilenameFunc
2876xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2877{
2878 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2879 if (old == NULL) {
2880 old = __xmlParserInputBufferCreateFilename;
2881 }
2882
2883 xmlParserInputBufferCreateFilenameValue = func;
2884 return(old);
2885}
2886
2887/**
2888 * xmlOutputBufferCreateFilenameDefault:
2889 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2890 *
2891 * Registers a callback for URI output file handling
2892 *
2893 * Returns the old value of the registration function
2894 */
2895xmlOutputBufferCreateFilenameFunc
2896xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2897{
2898 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2899#ifdef LIBXML_OUTPUT_ENABLED
2900 if (old == NULL) {
2901 old = __xmlOutputBufferCreateFilename;
2902 }
2903#endif
2904 xmlOutputBufferCreateFilenameValue = func;
2905 return(old);
2906}
2907
2908/**
Owen Taylor3473f882001-02-23 17:55:21 +00002909 * xmlParserInputBufferPush:
2910 * @in: a buffered parser input
2911 * @len: the size in bytes of the array.
2912 * @buf: an char array
2913 *
2914 * Push the content of the arry in the input buffer
2915 * This routine handle the I18N transcoding to internal UTF-8
2916 * This is used when operating the parser in progressive (push) mode.
2917 *
2918 * Returns the number of chars read and stored in the buffer, or -1
2919 * in case of error.
2920 */
2921int
2922xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2923 int len, const char *buf) {
2924 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002925 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002926
2927 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002928 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002929 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002930 unsigned int use;
2931
Owen Taylor3473f882001-02-23 17:55:21 +00002932 /*
2933 * Store the data in the incoming raw buffer
2934 */
2935 if (in->raw == NULL) {
2936 in->raw = xmlBufferCreate();
2937 }
William M. Bracka3215c72004-07-31 16:24:01 +00002938 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2939 if (ret != 0)
2940 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002941
2942 /*
2943 * convert as much as possible to the parser reading buffer.
2944 */
Daniel Veillard36711902004-02-11 13:25:26 +00002945 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002946 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2947 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002948 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002949 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002950 return(-1);
2951 }
Daniel Veillard36711902004-02-11 13:25:26 +00002952 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002953 } else {
2954 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002955 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2956 if (ret != 0)
2957 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002958 }
2959#ifdef DEBUG_INPUT
2960 xmlGenericError(xmlGenericErrorContext,
2961 "I/O: pushed %d chars, buffer %d/%d\n",
2962 nbchars, in->buffer->use, in->buffer->size);
2963#endif
2964 return(nbchars);
2965}
2966
2967/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002968 * endOfInput:
2969 *
2970 * When reading from an Input channel indicated end of file or error
2971 * don't reread from it again.
2972 */
2973static int
2974endOfInput (void * context ATTRIBUTE_UNUSED,
2975 char * buffer ATTRIBUTE_UNUSED,
2976 int len ATTRIBUTE_UNUSED) {
2977 return(0);
2978}
2979
2980/**
Owen Taylor3473f882001-02-23 17:55:21 +00002981 * xmlParserInputBufferGrow:
2982 * @in: a buffered parser input
2983 * @len: indicative value of the amount of chars to read
2984 *
2985 * Grow up the content of the input buffer, the old data are preserved
2986 * This routine handle the I18N transcoding to internal UTF-8
2987 * This routine is used when operating the parser in normal (pull) mode
2988 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002989 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002990 * onto in->buffer or in->raw
2991 *
2992 * Returns the number of chars read and stored in the buffer, or -1
2993 * in case of error.
2994 */
2995int
2996xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2997 char *buffer = NULL;
2998 int res = 0;
2999 int nbchars = 0;
3000 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00003001 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00003002
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003003 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003004 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003005 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003006
Owen Taylor3473f882001-02-23 17:55:21 +00003007 buffree = in->buffer->size - in->buffer->use;
3008 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003009 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003010 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003011 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003012 }
Owen Taylor3473f882001-02-23 17:55:21 +00003013
Daniel Veillarde5354492002-05-16 08:43:22 +00003014 needSize = in->buffer->use + len + 1;
3015 if (needSize > in->buffer->size){
3016 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003017 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003018 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003019 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003020 }
Owen Taylor3473f882001-02-23 17:55:21 +00003021 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003022 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003023
3024 /*
3025 * Call the read method for this I/O type.
3026 */
3027 if (in->readcallback != NULL) {
3028 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003029 if (res <= 0)
3030 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003031 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003032 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003033 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003034 return(-1);
3035 }
3036 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003037 return(-1);
3038 }
3039 len = res;
3040 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003041 unsigned int use;
3042
Owen Taylor3473f882001-02-23 17:55:21 +00003043 /*
3044 * Store the data in the incoming raw buffer
3045 */
3046 if (in->raw == NULL) {
3047 in->raw = xmlBufferCreate();
3048 }
William M. Bracka3215c72004-07-31 16:24:01 +00003049 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3050 if (res != 0)
3051 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003052
3053 /*
3054 * convert as much as possible to the parser reading buffer.
3055 */
Daniel Veillard36711902004-02-11 13:25:26 +00003056 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003057 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3058 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003059 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003060 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003061 return(-1);
3062 }
Daniel Veillard36711902004-02-11 13:25:26 +00003063 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003064 } else {
3065 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00003066 in->buffer->use += nbchars;
3067 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003068 }
3069#ifdef DEBUG_INPUT
3070 xmlGenericError(xmlGenericErrorContext,
3071 "I/O: read %d chars, buffer %d/%d\n",
3072 nbchars, in->buffer->use, in->buffer->size);
3073#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003074 return(nbchars);
3075}
3076
3077/**
3078 * xmlParserInputBufferRead:
3079 * @in: a buffered parser input
3080 * @len: indicative value of the amount of chars to read
3081 *
3082 * Refresh the content of the input buffer, the old data are considered
3083 * consumed
3084 * This routine handle the I18N transcoding to internal UTF-8
3085 *
3086 * Returns the number of chars read and stored in the buffer, or -1
3087 * in case of error.
3088 */
3089int
3090xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003091 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003092 if (in->readcallback != NULL)
3093 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003094 else if ((in->buffer != NULL) &&
3095 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3096 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003097 else
3098 return(-1);
3099}
3100
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003101#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003102/**
3103 * xmlOutputBufferWrite:
3104 * @out: a buffered parser output
3105 * @len: the size in bytes of the array.
3106 * @buf: an char array
3107 *
3108 * Write the content of the array in the output I/O buffer
3109 * This routine handle the I18N transcoding from internal UTF-8
3110 * The buffer is lossless, i.e. will store in case of partial
3111 * or delayed writes.
3112 *
3113 * Returns the number of chars immediately written, or -1
3114 * in case of error.
3115 */
3116int
3117xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3118 int nbchars = 0; /* number of chars to output to I/O */
3119 int ret; /* return from function call */
3120 int written = 0; /* number of char written to I/O so far */
3121 int chunk; /* number of byte curreent processed from buf */
3122
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003123 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003124 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003125 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003126
3127 do {
3128 chunk = len;
3129 if (chunk > 4 * MINLEN)
3130 chunk = 4 * MINLEN;
3131
3132 /*
3133 * first handle encoding stuff.
3134 */
3135 if (out->encoder != NULL) {
3136 /*
3137 * Store the data in the incoming raw buffer
3138 */
3139 if (out->conv == NULL) {
3140 out->conv = xmlBufferCreate();
3141 }
William M. Bracka3215c72004-07-31 16:24:01 +00003142 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3143 if (ret != 0)
3144 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003145
3146 if ((out->buffer->use < MINLEN) && (chunk == len))
3147 goto done;
3148
3149 /*
3150 * convert as much as possible to the parser reading buffer.
3151 */
3152 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003153 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003154 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003155 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003156 return(-1);
3157 }
3158 nbchars = out->conv->use;
3159 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003160 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3161 if (ret != 0)
3162 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003163 nbchars = out->buffer->use;
3164 }
3165 buf += chunk;
3166 len -= chunk;
3167
3168 if ((nbchars < MINLEN) && (len <= 0))
3169 goto done;
3170
3171 if (out->writecallback) {
3172 /*
3173 * second write the stuff to the I/O channel
3174 */
3175 if (out->encoder != NULL) {
3176 ret = out->writecallback(out->context,
3177 (const char *)out->conv->content, nbchars);
3178 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003179 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003180 } else {
3181 ret = out->writecallback(out->context,
3182 (const char *)out->buffer->content, nbchars);
3183 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003184 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003185 }
3186 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003187 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003188 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003189 return(ret);
3190 }
3191 out->written += ret;
3192 }
3193 written += nbchars;
3194 } while (len > 0);
3195
3196done:
3197#ifdef DEBUG_INPUT
3198 xmlGenericError(xmlGenericErrorContext,
3199 "I/O: wrote %d chars\n", written);
3200#endif
3201 return(written);
3202}
3203
3204/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003205 * xmlEscapeContent:
3206 * @out: a pointer to an array of bytes to store the result
3207 * @outlen: the length of @out
3208 * @in: a pointer to an array of unescaped UTF-8 bytes
3209 * @inlen: the length of @in
3210 *
3211 * Take a block of UTF-8 chars in and escape them.
3212 * Returns 0 if success, or -1 otherwise
3213 * The value of @inlen after return is the number of octets consumed
3214 * if the return value is positive, else unpredictable.
3215 * The value of @outlen after return is the number of octets consumed.
3216 */
3217static int
3218xmlEscapeContent(unsigned char* out, int *outlen,
3219 const xmlChar* in, int *inlen) {
3220 unsigned char* outstart = out;
3221 const unsigned char* base = in;
3222 unsigned char* outend = out + *outlen;
3223 const unsigned char* inend;
3224
3225 inend = in + (*inlen);
3226
3227 while ((in < inend) && (out < outend)) {
3228 if (*in == '<') {
3229 if (outend - out < 4) break;
3230 *out++ = '&';
3231 *out++ = 'l';
3232 *out++ = 't';
3233 *out++ = ';';
3234 } else if (*in == '>') {
3235 if (outend - out < 4) break;
3236 *out++ = '&';
3237 *out++ = 'g';
3238 *out++ = 't';
3239 *out++ = ';';
3240 } else if (*in == '&') {
3241 if (outend - out < 5) break;
3242 *out++ = '&';
3243 *out++ = 'a';
3244 *out++ = 'm';
3245 *out++ = 'p';
3246 *out++ = ';';
3247 } else if (*in == '\r') {
3248 if (outend - out < 5) break;
3249 *out++ = '&';
3250 *out++ = '#';
3251 *out++ = '1';
3252 *out++ = '3';
3253 *out++ = ';';
3254 } else {
3255 *out++ = (unsigned char) *in;
3256 }
3257 ++in;
3258 }
3259 *outlen = out - outstart;
3260 *inlen = in - base;
3261 return(0);
3262}
3263
3264/**
3265 * xmlOutputBufferWriteEscape:
3266 * @out: a buffered parser output
3267 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003268 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003269 *
3270 * Write the content of the string in the output I/O buffer
3271 * This routine escapes the caracters and then handle the I18N
3272 * transcoding from internal UTF-8
3273 * The buffer is lossless, i.e. will store in case of partial
3274 * or delayed writes.
3275 *
3276 * Returns the number of chars immediately written, or -1
3277 * in case of error.
3278 */
3279int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003280xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3281 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003282 int nbchars = 0; /* number of chars to output to I/O */
3283 int ret; /* return from function call */
3284 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003285 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003286 int chunk; /* number of byte currently processed from str */
3287 int len; /* number of bytes in str */
3288 int cons; /* byte from str consumed */
3289
Daniel Veillardce244ad2004-11-05 10:03:46 +00003290 if ((out == NULL) || (out->error) || (str == NULL) ||
3291 (out->buffer == NULL) ||
3292 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003293 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003294 if (len < 0) return(0);
3295 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003296 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003297
3298 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003299 oldwritten = written;
3300
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003301 /*
3302 * how many bytes to consume and how many bytes to store.
3303 */
3304 cons = len;
3305 chunk = (out->buffer->size - out->buffer->use) - 1;
3306
3307 /*
3308 * first handle encoding stuff.
3309 */
3310 if (out->encoder != NULL) {
3311 /*
3312 * Store the data in the incoming raw buffer
3313 */
3314 if (out->conv == NULL) {
3315 out->conv = xmlBufferCreate();
3316 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003317 ret = escaping(out->buffer->content + out->buffer->use ,
3318 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003319 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003320 return(-1);
3321 out->buffer->use += chunk;
3322 out->buffer->content[out->buffer->use] = 0;
3323
3324 if ((out->buffer->use < MINLEN) && (cons == len))
3325 goto done;
3326
3327 /*
3328 * convert as much as possible to the output buffer.
3329 */
3330 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3331 if ((ret < 0) && (ret != -3)) {
3332 xmlIOErr(XML_IO_ENCODER, NULL);
3333 out->error = XML_IO_ENCODER;
3334 return(-1);
3335 }
3336 nbchars = out->conv->use;
3337 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003338 ret = escaping(out->buffer->content + out->buffer->use ,
3339 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003340 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003341 return(-1);
3342 out->buffer->use += chunk;
3343 out->buffer->content[out->buffer->use] = 0;
3344 nbchars = out->buffer->use;
3345 }
3346 str += cons;
3347 len -= cons;
3348
3349 if ((nbchars < MINLEN) && (len <= 0))
3350 goto done;
3351
3352 if (out->writecallback) {
3353 /*
3354 * second write the stuff to the I/O channel
3355 */
3356 if (out->encoder != NULL) {
3357 ret = out->writecallback(out->context,
3358 (const char *)out->conv->content, nbchars);
3359 if (ret >= 0)
3360 xmlBufferShrink(out->conv, ret);
3361 } else {
3362 ret = out->writecallback(out->context,
3363 (const char *)out->buffer->content, nbchars);
3364 if (ret >= 0)
3365 xmlBufferShrink(out->buffer, ret);
3366 }
3367 if (ret < 0) {
3368 xmlIOErr(XML_IO_WRITE, NULL);
3369 out->error = XML_IO_WRITE;
3370 return(ret);
3371 }
3372 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003373 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3374 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003375 }
3376 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003377 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003378
3379done:
3380#ifdef DEBUG_INPUT
3381 xmlGenericError(xmlGenericErrorContext,
3382 "I/O: wrote %d chars\n", written);
3383#endif
3384 return(written);
3385}
3386
3387/**
Owen Taylor3473f882001-02-23 17:55:21 +00003388 * xmlOutputBufferWriteString:
3389 * @out: a buffered parser output
3390 * @str: a zero terminated C string
3391 *
3392 * Write the content of the string in the output I/O buffer
3393 * This routine handle the I18N transcoding from internal UTF-8
3394 * The buffer is lossless, i.e. will store in case of partial
3395 * or delayed writes.
3396 *
3397 * Returns the number of chars immediately written, or -1
3398 * in case of error.
3399 */
3400int
3401xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3402 int len;
3403
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003404 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003405 if (str == NULL)
3406 return(-1);
3407 len = strlen(str);
3408
3409 if (len > 0)
3410 return(xmlOutputBufferWrite(out, len, str));
3411 return(len);
3412}
3413
3414/**
3415 * xmlOutputBufferFlush:
3416 * @out: a buffered output
3417 *
3418 * flushes the output I/O channel
3419 *
3420 * Returns the number of byte written or -1 in case of error.
3421 */
3422int
3423xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3424 int nbchars = 0, ret = 0;
3425
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003426 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003427 /*
3428 * first handle encoding stuff.
3429 */
3430 if ((out->conv != NULL) && (out->encoder != NULL)) {
3431 /*
3432 * convert as much as possible to the parser reading buffer.
3433 */
3434 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3435 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003436 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003437 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003438 return(-1);
3439 }
3440 }
3441
3442 /*
3443 * second flush the stuff to the I/O channel
3444 */
3445 if ((out->conv != NULL) && (out->encoder != NULL) &&
3446 (out->writecallback != NULL)) {
3447 ret = out->writecallback(out->context,
3448 (const char *)out->conv->content, out->conv->use);
3449 if (ret >= 0)
3450 xmlBufferShrink(out->conv, ret);
3451 } else if (out->writecallback != NULL) {
3452 ret = out->writecallback(out->context,
3453 (const char *)out->buffer->content, out->buffer->use);
3454 if (ret >= 0)
3455 xmlBufferShrink(out->buffer, ret);
3456 }
3457 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003458 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003459 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003460 return(ret);
3461 }
3462 out->written += ret;
3463
3464#ifdef DEBUG_INPUT
3465 xmlGenericError(xmlGenericErrorContext,
3466 "I/O: flushed %d chars\n", ret);
3467#endif
3468 return(ret);
3469}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003470#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003471
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003472/**
Owen Taylor3473f882001-02-23 17:55:21 +00003473 * xmlParserGetDirectory:
3474 * @filename: the path to a file
3475 *
3476 * lookup the directory for that file
3477 *
3478 * Returns a new allocated string containing the directory, or NULL.
3479 */
3480char *
3481xmlParserGetDirectory(const char *filename) {
3482 char *ret = NULL;
3483 char dir[1024];
3484 char *cur;
3485 char sep = '/';
3486
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003487#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3488 return NULL;
3489#endif
3490
Owen Taylor3473f882001-02-23 17:55:21 +00003491 if (xmlInputCallbackInitialized == 0)
3492 xmlRegisterDefaultInputCallbacks();
3493
3494 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003495#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003496 sep = '\\';
3497#endif
3498
3499 strncpy(dir, filename, 1023);
3500 dir[1023] = 0;
3501 cur = &dir[strlen(dir)];
3502 while (cur > dir) {
3503 if (*cur == sep) break;
3504 cur --;
3505 }
3506 if (*cur == sep) {
3507 if (cur == dir) dir[1] = 0;
3508 else *cur = 0;
3509 ret = xmlMemStrdup(dir);
3510 } else {
3511 if (getcwd(dir, 1024) != NULL) {
3512 dir[1023] = 0;
3513 ret = xmlMemStrdup(dir);
3514 }
3515 }
3516 return(ret);
3517}
3518
3519/****************************************************************
3520 * *
3521 * External entities loading *
3522 * *
3523 ****************************************************************/
3524
Daniel Veillarda840b692003-10-19 13:35:37 +00003525/**
3526 * xmlCheckHTTPInput:
3527 * @ctxt: an XML parser context
3528 * @ret: an XML parser input
3529 *
3530 * Check an input in case it was created from an HTTP stream, in that
3531 * case it will handle encoding and update of the base URL in case of
3532 * redirection. It also checks for HTTP errors in which case the input
3533 * is cleanly freed up and an appropriate error is raised in context
3534 *
3535 * Returns the input or NULL in case of HTTP error.
3536 */
3537xmlParserInputPtr
3538xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3539#ifdef LIBXML_HTTP_ENABLED
3540 if ((ret != NULL) && (ret->buf != NULL) &&
3541 (ret->buf->readcallback == xmlIOHTTPRead) &&
3542 (ret->buf->context != NULL)) {
3543 const char *encoding;
3544 const char *redir;
3545 const char *mime;
3546 int code;
3547
3548 code = xmlNanoHTTPReturnCode(ret->buf->context);
3549 if (code >= 400) {
3550 /* fatal error */
3551 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003552 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003553 (const char *) ret->filename);
3554 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003555 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003556 xmlFreeInputStream(ret);
3557 ret = NULL;
3558 } else {
3559
3560 mime = xmlNanoHTTPMimeType(ret->buf->context);
3561 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3562 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3563 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3564 if (encoding != NULL) {
3565 xmlCharEncodingHandlerPtr handler;
3566
3567 handler = xmlFindCharEncodingHandler(encoding);
3568 if (handler != NULL) {
3569 xmlSwitchInputEncoding(ctxt, ret, handler);
3570 } else {
3571 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3572 "Unknown encoding %s",
3573 BAD_CAST encoding, NULL);
3574 }
3575 if (ret->encoding == NULL)
3576 ret->encoding = xmlStrdup(BAD_CAST encoding);
3577 }
3578#if 0
3579 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3580#endif
3581 }
3582 redir = xmlNanoHTTPRedir(ret->buf->context);
3583 if (redir != NULL) {
3584 if (ret->filename != NULL)
3585 xmlFree((xmlChar *) ret->filename);
3586 if (ret->directory != NULL) {
3587 xmlFree((xmlChar *) ret->directory);
3588 ret->directory = NULL;
3589 }
3590 ret->filename =
3591 (char *) xmlStrdup((const xmlChar *) redir);
3592 }
3593 }
3594 }
3595#endif
3596 return(ret);
3597}
3598
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003599static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003600 const char *path;
3601
3602 if (URL == NULL)
3603 return(0);
3604
Daniel Veillardf4862f02002-09-10 11:13:43 +00003605 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003606#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003607 path = &URL[17];
3608#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003609 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003610#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003611 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003612#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003613 path = &URL[8];
3614#else
3615 path = &URL[7];
3616#endif
3617 } else
3618 path = URL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003619
3620 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003621}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003622
Daniel Veillardad4e2962006-09-21 08:36:38 +00003623#ifdef LIBXML_CATALOG_ENABLED
3624
3625/**
3626 * xmlResolveResourceFromCatalog:
3627 * @URL: the URL for the entity to load
3628 * @ID: the System ID for the entity to load
3629 * @ctxt: the context in which the entity is called or NULL
3630 *
3631 * Resolves the URL and ID against the appropriate catalog.
3632 * This function is used by xmlDefaultExternalEntityLoader and
3633 * xmlNoNetExternalEntityLoader.
3634 *
3635 * Returns a new allocated URL, or NULL.
3636 */
3637xmlChar *
3638xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3639 xmlParserCtxtPtr ctxt) {
3640 xmlChar *resource = NULL;
3641 xmlCatalogAllow pref;
3642
3643 /*
3644 * If the resource doesn't exists as a file,
3645 * try to load it from the resource pointed in the catalogs
3646 */
3647 pref = xmlCatalogGetDefaults();
3648
3649 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3650 /*
3651 * Do a local lookup
3652 */
3653 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3654 ((pref == XML_CATA_ALLOW_ALL) ||
3655 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3656 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3657 (const xmlChar *)ID,
3658 (const xmlChar *)URL);
3659 }
3660 /*
3661 * Try a global lookup
3662 */
3663 if ((resource == NULL) &&
3664 ((pref == XML_CATA_ALLOW_ALL) ||
3665 (pref == XML_CATA_ALLOW_GLOBAL))) {
3666 resource = xmlCatalogResolve((const xmlChar *)ID,
3667 (const xmlChar *)URL);
3668 }
3669 if ((resource == NULL) && (URL != NULL))
3670 resource = xmlStrdup((const xmlChar *) URL);
3671
3672 /*
3673 * TODO: do an URI lookup on the reference
3674 */
3675 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3676 xmlChar *tmp = NULL;
3677
3678 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3679 ((pref == XML_CATA_ALLOW_ALL) ||
3680 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3681 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3682 }
3683 if ((tmp == NULL) &&
3684 ((pref == XML_CATA_ALLOW_ALL) ||
3685 (pref == XML_CATA_ALLOW_GLOBAL))) {
3686 tmp = xmlCatalogResolveURI(resource);
3687 }
3688
3689 if (tmp != NULL) {
3690 xmlFree(resource);
3691 resource = tmp;
3692 }
3693 }
3694 }
3695
3696 return resource;
3697}
3698
3699#endif
3700
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003701/**
Owen Taylor3473f882001-02-23 17:55:21 +00003702 * xmlDefaultExternalEntityLoader:
3703 * @URL: the URL for the entity to load
3704 * @ID: the System ID for the entity to load
3705 * @ctxt: the context in which the entity is called or NULL
3706 *
3707 * By default we don't load external entitites, yet.
3708 *
3709 * Returns a new allocated xmlParserInputPtr, or NULL.
3710 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003711static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003712xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003713 xmlParserCtxtPtr ctxt)
3714{
Owen Taylor3473f882001-02-23 17:55:21 +00003715 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003716 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003717
Owen Taylor3473f882001-02-23 17:55:21 +00003718#ifdef DEBUG_EXTERNAL_ENTITIES
3719 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003720 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003721#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00003722 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3723 int options = ctxt->options;
3724
3725 ctxt->options -= XML_PARSE_NONET;
3726 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3727 ctxt->options = options;
3728 return(ret);
3729 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003730#ifdef LIBXML_CATALOG_ENABLED
3731 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003732#endif
3733
3734 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003735 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003736
3737 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003738 if (ID == NULL)
3739 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003740 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003741 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003742 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003743 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003744 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003745 xmlFree(resource);
3746 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003747}
3748
3749static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3750 xmlDefaultExternalEntityLoader;
3751
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003752/**
Owen Taylor3473f882001-02-23 17:55:21 +00003753 * xmlSetExternalEntityLoader:
3754 * @f: the new entity resolver function
3755 *
3756 * Changes the defaultexternal entity resolver function for the application
3757 */
3758void
3759xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3760 xmlCurrentExternalEntityLoader = f;
3761}
3762
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003763/**
Owen Taylor3473f882001-02-23 17:55:21 +00003764 * xmlGetExternalEntityLoader:
3765 *
3766 * Get the default external entity resolver function for the application
3767 *
3768 * Returns the xmlExternalEntityLoader function pointer
3769 */
3770xmlExternalEntityLoader
3771xmlGetExternalEntityLoader(void) {
3772 return(xmlCurrentExternalEntityLoader);
3773}
3774
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003775/**
Owen Taylor3473f882001-02-23 17:55:21 +00003776 * xmlLoadExternalEntity:
3777 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003778 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003779 * @ctxt: the context in which the entity is called or NULL
3780 *
3781 * Load an external entity, note that the use of this function for
3782 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003783 *
3784 * Returns the xmlParserInputPtr or NULL
3785 */
3786xmlParserInputPtr
3787xmlLoadExternalEntity(const char *URL, const char *ID,
3788 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003789 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003790 char *canonicFilename;
3791 xmlParserInputPtr ret;
3792
3793 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3794 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003795 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003796 return(NULL);
3797 }
3798
3799 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3800 xmlFree(canonicFilename);
3801 return(ret);
3802 }
Owen Taylor3473f882001-02-23 17:55:21 +00003803 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3804}
3805
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003806/************************************************************************
3807 * *
3808 * Disabling Network access *
3809 * *
3810 ************************************************************************/
3811
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003812/**
3813 * xmlNoNetExternalEntityLoader:
3814 * @URL: the URL for the entity to load
3815 * @ID: the System ID for the entity to load
3816 * @ctxt: the context in which the entity is called or NULL
3817 *
3818 * A specific entity loader disabling network accesses, though still
3819 * allowing local catalog accesses for resolution.
3820 *
3821 * Returns a new allocated xmlParserInputPtr, or NULL.
3822 */
3823xmlParserInputPtr
3824xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3825 xmlParserCtxtPtr ctxt) {
3826 xmlParserInputPtr input = NULL;
3827 xmlChar *resource = NULL;
3828
3829#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00003830 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003831#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00003832
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003833 if (resource == NULL)
3834 resource = (xmlChar *) URL;
3835
3836 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003837 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3838 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003839 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003840 if (resource != (xmlChar *) URL)
3841 xmlFree(resource);
3842 return(NULL);
3843 }
3844 }
3845 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3846 if (resource != (xmlChar *) URL)
3847 xmlFree(resource);
3848 return(input);
3849}
3850
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003851#define bottom_xmlIO
3852#include "elfgcchack.h"