blob: 60e0a50ae3b3a9a1bc463293436645af45c5dbc6 [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
53#endif
54#ifdef HAVE_STAT
55# ifndef S_ISDIR
56# ifdef _S_ISDIR
57# define S_ISDIR(x) _S_ISDIR(x)
58# else
59# ifdef S_IFDIR
60# ifndef S_IFMT
61# ifdef _S_IFMT
62# define S_IFMT _S_IFMT
63# endif
64# endif
65# ifdef S_IFMT
66# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
67# endif
68# endif
69# endif
70# endif
71#endif
72
73#include <libxml/xmlmemory.h>
74#include <libxml/parser.h>
75#include <libxml/parserInternals.h>
76#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000077#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000078#include <libxml/nanohttp.h>
79#include <libxml/nanoftp.h>
80#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000081#ifdef LIBXML_CATALOG_ENABLED
82#include <libxml/catalog.h>
83#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000084#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000085
Daniel Veillardf012a642001-07-23 19:10:52 +000086/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000087/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000088/* #define DEBUG_INPUT */
89
90#ifdef DEBUG_INPUT
91#define MINLEN 40
92#else
93#define MINLEN 4000
94#endif
95
96/*
97 * Input I/O callback sets
98 */
99typedef struct _xmlInputCallback {
100 xmlInputMatchCallback matchcallback;
101 xmlInputOpenCallback opencallback;
102 xmlInputReadCallback readcallback;
103 xmlInputCloseCallback closecallback;
104} xmlInputCallback;
105
106#define MAX_INPUT_CALLBACK 15
107
Daniel Veillard22090732001-07-16 00:06:07 +0000108static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
109static int xmlInputCallbackNr = 0;
110static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000111
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000112#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000113/*
114 * Output I/O callback sets
115 */
116typedef struct _xmlOutputCallback {
117 xmlOutputMatchCallback matchcallback;
118 xmlOutputOpenCallback opencallback;
119 xmlOutputWriteCallback writecallback;
120 xmlOutputCloseCallback closecallback;
121} xmlOutputCallback;
122
123#define MAX_OUTPUT_CALLBACK 15
124
Daniel Veillard22090732001-07-16 00:06:07 +0000125static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
126static int xmlOutputCallbackNr = 0;
127static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000128#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000129
Daniel Veillard05d987b2003-10-08 11:54:57 +0000130/************************************************************************
131 * *
132 * Tree memory error handler *
133 * *
134 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000135
Daniel Veillard05d987b2003-10-08 11:54:57 +0000136static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000137 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000138 "Permission denied", /* EACCES */
139 "Resource temporarily unavailable",/* EAGAIN */
140 "Bad file descriptor", /* EBADF */
141 "Bad message", /* EBADMSG */
142 "Resource busy", /* EBUSY */
143 "Operation canceled", /* ECANCELED */
144 "No child processes", /* ECHILD */
145 "Resource deadlock avoided",/* EDEADLK */
146 "Domain error", /* EDOM */
147 "File exists", /* EEXIST */
148 "Bad address", /* EFAULT */
149 "File too large", /* EFBIG */
150 "Operation in progress", /* EINPROGRESS */
151 "Interrupted function call",/* EINTR */
152 "Invalid argument", /* EINVAL */
153 "Input/output error", /* EIO */
154 "Is a directory", /* EISDIR */
155 "Too many open files", /* EMFILE */
156 "Too many links", /* EMLINK */
157 "Inappropriate message buffer length",/* EMSGSIZE */
158 "Filename too long", /* ENAMETOOLONG */
159 "Too many open files in system",/* ENFILE */
160 "No such device", /* ENODEV */
161 "No such file or directory",/* ENOENT */
162 "Exec format error", /* ENOEXEC */
163 "No locks available", /* ENOLCK */
164 "Not enough space", /* ENOMEM */
165 "No space left on device", /* ENOSPC */
166 "Function not implemented", /* ENOSYS */
167 "Not a directory", /* ENOTDIR */
168 "Directory not empty", /* ENOTEMPTY */
169 "Not supported", /* ENOTSUP */
170 "Inappropriate I/O control operation",/* ENOTTY */
171 "No such device or address",/* ENXIO */
172 "Operation not permitted", /* EPERM */
173 "Broken pipe", /* EPIPE */
174 "Result too large", /* ERANGE */
175 "Read-only file system", /* EROFS */
176 "Invalid seek", /* ESPIPE */
177 "No such process", /* ESRCH */
178 "Operation timed out", /* ETIMEDOUT */
179 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000180 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000181 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000182 "flush error",
183 "write error",
184 "no input",
185 "buffer full",
186 "loading error",
187 "not a socket", /* ENOTSOCK */
188 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000189 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000190 "unreachable network", /* ENETUNREACH */
191 "adddress in use", /* EADDRINUSE */
192 "already in use", /* EALREADY */
193 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000194};
195
Daniel Veillardf7416012006-04-27 08:15:20 +0000196#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
197/**
198 * __xmlIOWin32UTF8ToWChar:
199 * @u8String: uft-8 string
200 *
201 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
202 */
203static wchar_t *
204__xmlIOWin32UTF8ToWChar(const char *u8String)
205{
206 wchar_t *wString = NULL;
207
208 if (u8String)
209 {
210 int wLen = MultiByteToWideChar(CP_UTF8,0,u8String,-1,NULL,0);
211 if (wLen)
212 {
213 wString = malloc((wLen+1) * sizeof(wchar_t));
214 if (wString)
215 {
216 if (MultiByteToWideChar(CP_UTF8,0,u8String,-1,wString,wLen+1) == 0)
217 {
218 free(wString);
219 wString = NULL;
220 }
221 }
222 }
223 }
224
225 return wString;
226}
227#endif
228
Daniel Veillard05d987b2003-10-08 11:54:57 +0000229/**
230 * xmlIOErrMemory:
231 * @extra: extra informations
232 *
233 * Handle an out of memory condition
234 */
235static void
236xmlIOErrMemory(const char *extra)
237{
238 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
239}
240
241/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000242 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000243 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000244 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000245 * @extra: extra informations
246 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000247 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000248 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000249void
250__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000251{
252 unsigned int idx;
253
254 if (code == 0) {
255#ifdef HAVE_ERRNO_H
256 if (errno == 0) code = 0;
257#ifdef EACCES
258 else if (errno == EACCES) code = XML_IO_EACCES;
259#endif
260#ifdef EAGAIN
261 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
262#endif
263#ifdef EBADF
264 else if (errno == EBADF) code = XML_IO_EBADF;
265#endif
266#ifdef EBADMSG
267 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
268#endif
269#ifdef EBUSY
270 else if (errno == EBUSY) code = XML_IO_EBUSY;
271#endif
272#ifdef ECANCELED
273 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
274#endif
275#ifdef ECHILD
276 else if (errno == ECHILD) code = XML_IO_ECHILD;
277#endif
278#ifdef EDEADLK
279 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
280#endif
281#ifdef EDOM
282 else if (errno == EDOM) code = XML_IO_EDOM;
283#endif
284#ifdef EEXIST
285 else if (errno == EEXIST) code = XML_IO_EEXIST;
286#endif
287#ifdef EFAULT
288 else if (errno == EFAULT) code = XML_IO_EFAULT;
289#endif
290#ifdef EFBIG
291 else if (errno == EFBIG) code = XML_IO_EFBIG;
292#endif
293#ifdef EINPROGRESS
294 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
295#endif
296#ifdef EINTR
297 else if (errno == EINTR) code = XML_IO_EINTR;
298#endif
299#ifdef EINVAL
300 else if (errno == EINVAL) code = XML_IO_EINVAL;
301#endif
302#ifdef EIO
303 else if (errno == EIO) code = XML_IO_EIO;
304#endif
305#ifdef EISDIR
306 else if (errno == EISDIR) code = XML_IO_EISDIR;
307#endif
308#ifdef EMFILE
309 else if (errno == EMFILE) code = XML_IO_EMFILE;
310#endif
311#ifdef EMLINK
312 else if (errno == EMLINK) code = XML_IO_EMLINK;
313#endif
314#ifdef EMSGSIZE
315 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
316#endif
317#ifdef ENAMETOOLONG
318 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
319#endif
320#ifdef ENFILE
321 else if (errno == ENFILE) code = XML_IO_ENFILE;
322#endif
323#ifdef ENODEV
324 else if (errno == ENODEV) code = XML_IO_ENODEV;
325#endif
326#ifdef ENOENT
327 else if (errno == ENOENT) code = XML_IO_ENOENT;
328#endif
329#ifdef ENOEXEC
330 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
331#endif
332#ifdef ENOLCK
333 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
334#endif
335#ifdef ENOMEM
336 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
337#endif
338#ifdef ENOSPC
339 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
340#endif
341#ifdef ENOSYS
342 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
343#endif
344#ifdef ENOTDIR
345 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
346#endif
347#ifdef ENOTEMPTY
348 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
349#endif
350#ifdef ENOTSUP
351 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
352#endif
353#ifdef ENOTTY
354 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
355#endif
356#ifdef ENXIO
357 else if (errno == ENXIO) code = XML_IO_ENXIO;
358#endif
359#ifdef EPERM
360 else if (errno == EPERM) code = XML_IO_EPERM;
361#endif
362#ifdef EPIPE
363 else if (errno == EPIPE) code = XML_IO_EPIPE;
364#endif
365#ifdef ERANGE
366 else if (errno == ERANGE) code = XML_IO_ERANGE;
367#endif
368#ifdef EROFS
369 else if (errno == EROFS) code = XML_IO_EROFS;
370#endif
371#ifdef ESPIPE
372 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
373#endif
374#ifdef ESRCH
375 else if (errno == ESRCH) code = XML_IO_ESRCH;
376#endif
377#ifdef ETIMEDOUT
378 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
379#endif
380#ifdef EXDEV
381 else if (errno == EXDEV) code = XML_IO_EXDEV;
382#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000383#ifdef ENOTSOCK
384 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
385#endif
386#ifdef EISCONN
387 else if (errno == EISCONN) code = XML_IO_EISCONN;
388#endif
389#ifdef ECONNREFUSED
390 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
391#endif
392#ifdef ETIMEDOUT
393 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
394#endif
395#ifdef ENETUNREACH
396 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
397#endif
398#ifdef EADDRINUSE
399 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
400#endif
401#ifdef EINPROGRESS
402 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
403#endif
404#ifdef EALREADY
405 else if (errno == EALREADY) code = XML_IO_EALREADY;
406#endif
407#ifdef EAFNOSUPPORT
408 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
409#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000410 else code = XML_IO_UNKNOWN;
411#endif /* HAVE_ERRNO_H */
412 }
413 idx = 0;
414 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
415 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
416
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000417 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
418}
419
420/**
421 * xmlIOErr:
422 * @code: the error number
423 * @extra: extra informations
424 *
425 * Handle an I/O error
426 */
427static void
428xmlIOErr(int code, const char *extra)
429{
430 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000431}
432
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000433/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000434 * __xmlLoaderErr:
435 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000436 * @extra: extra informations
437 *
438 * Handle a resource access error
439 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000440void
441__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000442{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000443 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000444 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000445 xmlGenericErrorFunc channel = NULL;
446 void *data = NULL;
447 xmlErrorLevel level = XML_ERR_ERROR;
448
Daniel Veillard157fee02003-10-31 10:36:03 +0000449 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
450 (ctxt->instate == XML_PARSER_EOF))
451 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000452 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
453 if (ctxt->validate) {
454 channel = ctxt->sax->error;
455 level = XML_ERR_ERROR;
456 } else {
457 channel = ctxt->sax->warning;
458 level = XML_ERR_WARNING;
459 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000460 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
461 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000462 data = ctxt->userData;
463 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000464 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000465 XML_IO_LOAD_ERROR, level, NULL, 0,
466 filename, NULL, NULL, 0, 0,
467 msg, filename);
468
469}
470
Daniel Veillard05d987b2003-10-08 11:54:57 +0000471/************************************************************************
472 * *
473 * Tree memory error handler *
474 * *
475 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000476/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000477 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000478 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000479 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000480 * This function is obsolete. Please see xmlURIFromPath in uri.c for
481 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000482 *
483 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000484 */
485xmlChar *
486xmlNormalizeWindowsPath(const xmlChar *path)
487{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000488 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000489}
490
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000491/**
492 * xmlCleanupInputCallbacks:
493 *
494 * clears the entire input callback table. this includes the
495 * compiled-in I/O.
496 */
497void
498xmlCleanupInputCallbacks(void)
499{
500 int i;
501
502 if (!xmlInputCallbackInitialized)
503 return;
504
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000505 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000506 xmlInputCallbackTable[i].matchcallback = NULL;
507 xmlInputCallbackTable[i].opencallback = NULL;
508 xmlInputCallbackTable[i].readcallback = NULL;
509 xmlInputCallbackTable[i].closecallback = NULL;
510 }
511
512 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000513 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000514}
515
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000516/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000517 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000518 *
519 * Clear the top input callback from the input stack. this includes the
520 * compiled-in I/O.
521 *
522 * Returns the number of input callback registered or -1 in case of error.
523 */
524int
525xmlPopInputCallbacks(void)
526{
527 if (!xmlInputCallbackInitialized)
528 return(-1);
529
530 if (xmlInputCallbackNr <= 0)
531 return(-1);
532
533 xmlInputCallbackNr--;
534 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
535 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
536 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
537 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
538
539 return(xmlInputCallbackNr);
540}
541
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000542#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000543/**
544 * xmlCleanupOutputCallbacks:
545 *
546 * clears the entire output callback table. this includes the
547 * compiled-in I/O callbacks.
548 */
549void
550xmlCleanupOutputCallbacks(void)
551{
552 int i;
553
554 if (!xmlOutputCallbackInitialized)
555 return;
556
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000557 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000558 xmlOutputCallbackTable[i].matchcallback = NULL;
559 xmlOutputCallbackTable[i].opencallback = NULL;
560 xmlOutputCallbackTable[i].writecallback = NULL;
561 xmlOutputCallbackTable[i].closecallback = NULL;
562 }
563
564 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000565 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000566}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000567#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000568
Owen Taylor3473f882001-02-23 17:55:21 +0000569/************************************************************************
570 * *
571 * Standard I/O for file accesses *
572 * *
573 ************************************************************************/
574
575/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000576 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000577 * @path: the path to check
578 *
579 * function checks to see if @path is a valid source
580 * (file, socket...) for XML.
581 *
582 * if stat is not available on the target machine,
583 * returns 1. if stat fails, returns 0 (if calling
584 * stat on the filename fails, it can't be right).
585 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000586 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000587 */
588
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000589int
Owen Taylor3473f882001-02-23 17:55:21 +0000590xmlCheckFilename (const char *path)
591{
Daniel Veillard0b309952006-05-02 20:34:38 +0000592#ifdef HAVE_STAT
593 struct stat stat_buffer;
594#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000595 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000596 return(0);
Daniel Veillardf7416012006-04-27 08:15:20 +0000597
598#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
599 {
600 int retval = 0;
601
602 wchar_t *wPath = __xmlIOWin32UTF8ToWChar(path);
603 if (wPath)
604 {
605 struct _stat stat_buffer;
606
607 if (_wstat(wPath,&stat_buffer) == 0)
608 {
609 retval = 1;
610
611 if (((stat_buffer.st_mode & S_IFDIR) == S_IFDIR))
612 retval = 2;
613 }
614
615 free(wPath);
616 }
617
618 return retval;
619 }
620#else
Owen Taylor3473f882001-02-23 17:55:21 +0000621#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000622 if (stat(path, &stat_buffer) == -1)
623 return 0;
624
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000625#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000626 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000627 return 2;
Daniel Veillardf7416012006-04-27 08:15:20 +0000628#endif /* S_ISDIR */
629#endif /* HAVE_STAT */
630#endif /* WIN32 */
Daniel Veillard34099b42004-11-04 17:34:35 +0000631
Owen Taylor3473f882001-02-23 17:55:21 +0000632 return 1;
633}
634
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000635static int
Owen Taylor3473f882001-02-23 17:55:21 +0000636xmlNop(void) {
637 return(0);
638}
639
640/**
Owen Taylor3473f882001-02-23 17:55:21 +0000641 * xmlFdRead:
642 * @context: the I/O context
643 * @buffer: where to drop data
644 * @len: number of bytes to read
645 *
646 * Read @len bytes to @buffer from the I/O channel.
647 *
648 * Returns the number of bytes written
649 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000650static int
Owen Taylor3473f882001-02-23 17:55:21 +0000651xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000652 int ret;
653
654 ret = read((int) (long) context, &buffer[0], len);
655 if (ret < 0) xmlIOErr(0, "read()");
656 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000657}
658
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000659#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000660/**
661 * xmlFdWrite:
662 * @context: the I/O context
663 * @buffer: where to get data
664 * @len: number of bytes to write
665 *
666 * Write @len bytes from @buffer to the I/O channel.
667 *
668 * Returns the number of bytes written
669 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000670static int
Owen Taylor3473f882001-02-23 17:55:21 +0000671xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000672 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000673
Daniel Veillard9b693b42005-10-28 14:54:17 +0000674 if (len > 0) {
675 ret = write((int) (long) context, &buffer[0], len);
676 if (ret < 0) xmlIOErr(0, "write()");
677 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000678 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000679}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000680#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000681
682/**
683 * xmlFdClose:
684 * @context: the I/O context
685 *
686 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000687 *
688 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000689 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000690static int
Owen Taylor3473f882001-02-23 17:55:21 +0000691xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000692 int ret;
693 ret = close((int) (long) context);
694 if (ret < 0) xmlIOErr(0, "close()");
695 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000696}
697
698/**
699 * xmlFileMatch:
700 * @filename: the URI for matching
701 *
702 * input from FILE *
703 *
704 * Returns 1 if matches, 0 otherwise
705 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000706int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000707xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000708 return(1);
709}
710
711/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000712 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000713 * @filename: the URI for matching
714 *
715 * input from FILE *, supports compressed input
716 * if @filename is " " then the standard input is used
717 *
718 * Returns an I/O context or NULL in case of error
719 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000720static void *
721xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000722 const char *path = NULL;
723 FILE *fd;
724
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000725 if (filename == NULL)
726 return(NULL);
727
Owen Taylor3473f882001-02-23 17:55:21 +0000728 if (!strcmp(filename, "-")) {
729 fd = stdin;
730 return((void *) fd);
731 }
732
Daniel Veillardf4862f02002-09-10 11:13:43 +0000733 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000734#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000735 path = &filename[17];
736#else
Owen Taylor3473f882001-02-23 17:55:21 +0000737 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000738#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000739 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000740#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000741 path = &filename[8];
742#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000743 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000744#endif
745 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000746 path = filename;
747
748 if (path == NULL)
749 return(NULL);
750 if (!xmlCheckFilename(path))
751 return(NULL);
752
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000753#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000754 {
755 wchar_t *wPath = __xmlIOWin32UTF8ToWChar(path);
756 if (wPath)
757 {
758 fd = _wfopen(wPath, L"rb");
759 free(wPath);
760 }
761 else
762 {
763 fd = fopen(path, "rb");
764 }
765 }
Owen Taylor3473f882001-02-23 17:55:21 +0000766#else
767 fd = fopen(path, "r");
768#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000769 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000770 return((void *) fd);
771}
772
773/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000774 * xmlFileOpen:
775 * @filename: the URI for matching
776 *
777 * Wrapper around xmlFileOpen_real that try it with an unescaped
778 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000779 *
780 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000781 */
782void *
783xmlFileOpen (const char *filename) {
784 char *unescaped;
785 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000786
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000787 unescaped = xmlURIUnescapeString(filename, 0, NULL);
788 if (unescaped != NULL) {
789 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000790 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000791 } else {
792 retval = xmlFileOpen_real(filename);
793 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000794 return retval;
795}
796
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000797#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000798/**
Owen Taylor3473f882001-02-23 17:55:21 +0000799 * xmlFileOpenW:
800 * @filename: the URI for matching
801 *
802 * output to from FILE *,
803 * if @filename is "-" then the standard output is used
804 *
805 * Returns an I/O context or NULL in case of error
806 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000807static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000808xmlFileOpenW (const char *filename) {
809 const char *path = NULL;
810 FILE *fd;
811
812 if (!strcmp(filename, "-")) {
813 fd = stdout;
814 return((void *) fd);
815 }
816
Daniel Veillardf4862f02002-09-10 11:13:43 +0000817 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000818#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000819 path = &filename[17];
820#else
Owen Taylor3473f882001-02-23 17:55:21 +0000821 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000822#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000823 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000824#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000825 path = &filename[8];
826#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000827 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000828#endif
829 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000830 path = filename;
831
832 if (path == NULL)
833 return(NULL);
834
Daniel Veillardf7416012006-04-27 08:15:20 +0000835#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
836 {
837 wchar_t *wPath = __xmlIOWin32UTF8ToWChar(path);
838 if (wPath)
839 {
840 fd = _wfopen(wPath, L"wb");
841 free(wPath);
842 }
843 else
844 {
845 fd = fopen(path, "wb");
846 }
847 }
848#else
849 fd = fopen(path, "wb");
850#endif /* WIN32 */
851
852 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000853 return((void *) fd);
854}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000855#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000856
857/**
858 * xmlFileRead:
859 * @context: the I/O context
860 * @buffer: where to drop data
861 * @len: number of bytes to write
862 *
863 * Read @len bytes to @buffer from the I/O channel.
864 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000865 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000866 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000867int
Owen Taylor3473f882001-02-23 17:55:21 +0000868xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000869 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000870 if ((context == NULL) || (buffer == NULL))
871 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000872 ret = fread(&buffer[0], 1, len, (FILE *) context);
873 if (ret < 0) xmlIOErr(0, "fread()");
874 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000875}
876
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000877#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000878/**
879 * xmlFileWrite:
880 * @context: the I/O context
881 * @buffer: where to drop data
882 * @len: number of bytes to write
883 *
884 * Write @len bytes from @buffer to the I/O channel.
885 *
886 * Returns the number of bytes written
887 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000888static int
Owen Taylor3473f882001-02-23 17:55:21 +0000889xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000890 int items;
891
Daniel Veillardce682bc2004-11-05 17:22:25 +0000892 if ((context == NULL) || (buffer == NULL))
893 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000894 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000895 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000896 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000897 return(-1);
898 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000899 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000900}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000901#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000902
903/**
904 * xmlFileClose:
905 * @context: the I/O context
906 *
907 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000908 *
909 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000910 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000911int
Owen Taylor3473f882001-02-23 17:55:21 +0000912xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000913 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000914 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000915
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000916 if (context == NULL)
917 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000918 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000919 if ((fil == stdout) || (fil == stderr)) {
920 ret = fflush(fil);
921 if (ret < 0)
922 xmlIOErr(0, "fflush()");
923 return(0);
924 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000925 if (fil == stdin)
926 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000927 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
928 if (ret < 0)
929 xmlIOErr(0, "fclose()");
930 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000931}
932
933/**
934 * xmlFileFlush:
935 * @context: the I/O context
936 *
937 * Flush an I/O channel
938 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000939static int
Owen Taylor3473f882001-02-23 17:55:21 +0000940xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000941 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000942
943 if (context == NULL)
944 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000945 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
946 if (ret < 0)
947 xmlIOErr(0, "fflush()");
948 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000949}
950
Daniel Veillard9a00fd22005-11-09 08:56:26 +0000951#ifdef LIBXML_OUTPUT_ENABLED
952/**
953 * xmlBufferWrite:
954 * @context: the xmlBuffer
955 * @buffer: the data to write
956 * @len: number of bytes to write
957 *
958 * Write @len bytes from @buffer to the xml buffer
959 *
960 * Returns the number of bytes written
961 */
962static int
963xmlBufferWrite (void * context, const char * buffer, int len) {
964 int ret;
965
966 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
967 if (ret != 0)
968 return(-1);
969 return(len);
970}
Daniel Veillard9a00fd22005-11-09 08:56:26 +0000971#endif
972
Owen Taylor3473f882001-02-23 17:55:21 +0000973#ifdef HAVE_ZLIB_H
974/************************************************************************
975 * *
976 * I/O for compressed file accesses *
977 * *
978 ************************************************************************/
979/**
980 * xmlGzfileMatch:
981 * @filename: the URI for matching
982 *
983 * input from compressed file test
984 *
985 * Returns 1 if matches, 0 otherwise
986 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000987static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000988xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000989 return(1);
990}
991
992/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000993 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000994 * @filename: the URI for matching
995 *
996 * input from compressed file open
997 * if @filename is " " then the standard input is used
998 *
999 * Returns an I/O context or NULL in case of error
1000 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001001static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001002xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001003 const char *path = NULL;
1004 gzFile fd;
1005
1006 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001007 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001008 return((void *) fd);
1009 }
1010
Daniel Veillardf4862f02002-09-10 11:13:43 +00001011 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001012#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001013 path = &filename[17];
1014#else
Owen Taylor3473f882001-02-23 17:55:21 +00001015 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001016#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001017 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001018#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001019 path = &filename[8];
1020#else
Owen Taylor3473f882001-02-23 17:55:21 +00001021 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001022#endif
1023 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001024 path = filename;
1025
1026 if (path == NULL)
1027 return(NULL);
1028 if (!xmlCheckFilename(path))
1029 return(NULL);
1030
1031 fd = gzopen(path, "rb");
1032 return((void *) fd);
1033}
1034
1035/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001036 * xmlGzfileOpen:
1037 * @filename: the URI for matching
1038 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001039 * Wrapper around xmlGzfileOpen if the open fais, it will
1040 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001041 */
1042static void *
1043xmlGzfileOpen (const char *filename) {
1044 char *unescaped;
1045 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001046
1047 retval = xmlGzfileOpen_real(filename);
1048 if (retval == NULL) {
1049 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1050 if (unescaped != NULL) {
1051 retval = xmlGzfileOpen_real(unescaped);
1052 }
1053 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001054 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001055 return retval;
1056}
1057
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001058#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001059/**
Owen Taylor3473f882001-02-23 17:55:21 +00001060 * xmlGzfileOpenW:
1061 * @filename: the URI for matching
1062 * @compression: the compression factor (0 - 9 included)
1063 *
1064 * input from compressed file open
1065 * if @filename is " " then the standard input is used
1066 *
1067 * Returns an I/O context or NULL in case of error
1068 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001069static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001070xmlGzfileOpenW (const char *filename, int compression) {
1071 const char *path = NULL;
1072 char mode[15];
1073 gzFile fd;
1074
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001075 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001076 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001077 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001078 return((void *) fd);
1079 }
1080
Daniel Veillardf4862f02002-09-10 11:13:43 +00001081 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001082#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001083 path = &filename[17];
1084#else
Owen Taylor3473f882001-02-23 17:55:21 +00001085 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001086#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001087 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001088#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001089 path = &filename[8];
1090#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001091 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001092#endif
1093 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001094 path = filename;
1095
1096 if (path == NULL)
1097 return(NULL);
1098
1099 fd = gzopen(path, mode);
1100 return((void *) fd);
1101}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001102#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001103
1104/**
1105 * xmlGzfileRead:
1106 * @context: the I/O context
1107 * @buffer: where to drop data
1108 * @len: number of bytes to write
1109 *
1110 * Read @len bytes to @buffer from the compressed I/O channel.
1111 *
1112 * Returns the number of bytes written
1113 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001114static int
Owen Taylor3473f882001-02-23 17:55:21 +00001115xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001116 int ret;
1117
1118 ret = gzread((gzFile) context, &buffer[0], len);
1119 if (ret < 0) xmlIOErr(0, "gzread()");
1120 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001121}
1122
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001123#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001124/**
1125 * xmlGzfileWrite:
1126 * @context: the I/O context
1127 * @buffer: where to drop data
1128 * @len: number of bytes to write
1129 *
1130 * Write @len bytes from @buffer to the compressed I/O channel.
1131 *
1132 * Returns the number of bytes written
1133 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001134static int
Owen Taylor3473f882001-02-23 17:55:21 +00001135xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001136 int ret;
1137
1138 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1139 if (ret < 0) xmlIOErr(0, "gzwrite()");
1140 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001141}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001142#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001143
1144/**
1145 * xmlGzfileClose:
1146 * @context: the I/O context
1147 *
1148 * Close a compressed I/O channel
1149 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001150static int
Owen Taylor3473f882001-02-23 17:55:21 +00001151xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001152 int ret;
1153
1154 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1155 if (ret < 0) xmlIOErr(0, "gzclose()");
1156 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001157}
1158#endif /* HAVE_ZLIB_H */
1159
1160#ifdef LIBXML_HTTP_ENABLED
1161/************************************************************************
1162 * *
1163 * I/O for HTTP file accesses *
1164 * *
1165 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001166
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001167#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001168typedef struct xmlIOHTTPWriteCtxt_
1169{
1170 int compression;
1171
1172 char * uri;
1173
1174 void * doc_buff;
1175
1176} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1177
1178#ifdef HAVE_ZLIB_H
1179
1180#define DFLT_WBITS ( -15 )
1181#define DFLT_MEM_LVL ( 8 )
1182#define GZ_MAGIC1 ( 0x1f )
1183#define GZ_MAGIC2 ( 0x8b )
1184#define LXML_ZLIB_OS_CODE ( 0x03 )
1185#define INIT_HTTP_BUFF_SIZE ( 32768 )
1186#define DFLT_ZLIB_RATIO ( 5 )
1187
1188/*
1189** Data structure and functions to work with sending compressed data
1190** via HTTP.
1191*/
1192
1193typedef struct xmlZMemBuff_
1194{
1195 unsigned long size;
1196 unsigned long crc;
1197
1198 unsigned char * zbuff;
1199 z_stream zctrl;
1200
1201} xmlZMemBuff, *xmlZMemBuffPtr;
1202
1203/**
1204 * append_reverse_ulong
1205 * @buff: Compressed memory buffer
1206 * @data: Unsigned long to append
1207 *
1208 * Append a unsigned long in reverse byte order to the end of the
1209 * memory buffer.
1210 */
1211static void
1212append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1213
1214 int idx;
1215
1216 if ( buff == NULL )
1217 return;
1218
1219 /*
1220 ** This is plagiarized from putLong in gzio.c (zlib source) where
1221 ** the number "4" is hardcoded. If zlib is ever patched to
1222 ** support 64 bit file sizes, this code would need to be patched
1223 ** as well.
1224 */
1225
1226 for ( idx = 0; idx < 4; idx++ ) {
1227 *buff->zctrl.next_out = ( data & 0xff );
1228 data >>= 8;
1229 buff->zctrl.next_out++;
1230 }
1231
1232 return;
1233}
1234
1235/**
1236 *
1237 * xmlFreeZMemBuff
1238 * @buff: The memory buffer context to clear
1239 *
1240 * Release all the resources associated with the compressed memory buffer.
1241 */
1242static void
1243xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001244
1245#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001246 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001247#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001248
1249 if ( buff == NULL )
1250 return;
1251
1252 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001253#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001254 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001255 if ( z_err != Z_OK )
1256 xmlGenericError( xmlGenericErrorContext,
1257 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1258 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001259#else
1260 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001261#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001262
1263 xmlFree( buff );
1264 return;
1265}
1266
1267/**
1268 * xmlCreateZMemBuff
1269 *@compression: Compression value to use
1270 *
1271 * Create a memory buffer to hold the compressed XML document. The
1272 * compressed document in memory will end up being identical to what
1273 * would be created if gzopen/gzwrite/gzclose were being used to
1274 * write the document to disk. The code for the header/trailer data to
1275 * the compression is plagiarized from the zlib source files.
1276 */
1277static void *
1278xmlCreateZMemBuff( int compression ) {
1279
1280 int z_err;
1281 int hdr_lgth;
1282 xmlZMemBuffPtr buff = NULL;
1283
1284 if ( ( compression < 1 ) || ( compression > 9 ) )
1285 return ( NULL );
1286
1287 /* Create the control and data areas */
1288
1289 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1290 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001291 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001292 return ( NULL );
1293 }
1294
1295 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1296 buff->size = INIT_HTTP_BUFF_SIZE;
1297 buff->zbuff = xmlMalloc( buff->size );
1298 if ( buff->zbuff == NULL ) {
1299 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001300 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001301 return ( NULL );
1302 }
1303
1304 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1305 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1306 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001307 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001308 xmlFreeZMemBuff( buff );
1309 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001310 xmlStrPrintf(msg, 500,
1311 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1312 "Error initializing compression context. ZLIB error:",
1313 z_err );
1314 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001315 return ( NULL );
1316 }
1317
1318 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001319 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001320 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1321 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001322 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1323 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1324 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1325 buff->zctrl.avail_out = buff->size - hdr_lgth;
1326
1327 return ( buff );
1328}
1329
1330/**
1331 * xmlZMemBuffExtend
1332 * @buff: Buffer used to compress and consolidate data.
1333 * @ext_amt: Number of bytes to extend the buffer.
1334 *
1335 * Extend the internal buffer used to store the compressed data by the
1336 * specified amount.
1337 *
1338 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1339 * the original buffer still exists at the original size.
1340 */
1341static int
1342xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1343
1344 int rc = -1;
1345 size_t new_size;
1346 size_t cur_used;
1347
1348 unsigned char * tmp_ptr = NULL;
1349
1350 if ( buff == NULL )
1351 return ( -1 );
1352
1353 else if ( ext_amt == 0 )
1354 return ( 0 );
1355
1356 cur_used = buff->zctrl.next_out - buff->zbuff;
1357 new_size = buff->size + ext_amt;
1358
1359#ifdef DEBUG_HTTP
1360 if ( cur_used > new_size )
1361 xmlGenericError( xmlGenericErrorContext,
1362 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1363 "Buffer overwrite detected during compressed memory",
1364 "buffer extension. Overflowed by",
1365 (cur_used - new_size ) );
1366#endif
1367
1368 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1369 if ( tmp_ptr != NULL ) {
1370 rc = 0;
1371 buff->size = new_size;
1372 buff->zbuff = tmp_ptr;
1373 buff->zctrl.next_out = tmp_ptr + cur_used;
1374 buff->zctrl.avail_out = new_size - cur_used;
1375 }
1376 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001377 xmlChar msg[500];
1378 xmlStrPrintf(msg, 500,
1379 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1380 "Allocation failure extending output buffer to",
1381 new_size );
1382 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001383 }
1384
1385 return ( rc );
1386}
1387
1388/**
1389 * xmlZMemBuffAppend
1390 * @buff: Buffer used to compress and consolidate data
1391 * @src: Uncompressed source content to append to buffer
1392 * @len: Length of source data to append to buffer
1393 *
1394 * Compress and append data to the internal buffer. The data buffer
1395 * will be expanded if needed to store the additional data.
1396 *
1397 * Returns the number of bytes appended to the buffer or -1 on error.
1398 */
1399static int
1400xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1401
1402 int z_err;
1403 size_t min_accept;
1404
1405 if ( ( buff == NULL ) || ( src == NULL ) )
1406 return ( -1 );
1407
1408 buff->zctrl.avail_in = len;
1409 buff->zctrl.next_in = (unsigned char *)src;
1410 while ( buff->zctrl.avail_in > 0 ) {
1411 /*
1412 ** Extend the buffer prior to deflate call if a reasonable amount
1413 ** of output buffer space is not available.
1414 */
1415 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1416 if ( buff->zctrl.avail_out <= min_accept ) {
1417 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1418 return ( -1 );
1419 }
1420
1421 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1422 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001423 xmlChar msg[500];
1424 xmlStrPrintf(msg, 500,
1425 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001426 "Compression error while appending",
1427 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001428 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001429 return ( -1 );
1430 }
1431 }
1432
1433 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1434
1435 return ( len );
1436}
1437
1438/**
1439 * xmlZMemBuffGetContent
1440 * @buff: Compressed memory content buffer
1441 * @data_ref: Pointer reference to point to compressed content
1442 *
1443 * Flushes the compression buffers, appends gzip file trailers and
1444 * returns the compressed content and length of the compressed data.
1445 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1446 *
1447 * Returns the length of the compressed data or -1 on error.
1448 */
1449static int
1450xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1451
1452 int zlgth = -1;
1453 int z_err;
1454
1455 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1456 return ( -1 );
1457
1458 /* Need to loop until compression output buffers are flushed */
1459
1460 do
1461 {
1462 z_err = deflate( &buff->zctrl, Z_FINISH );
1463 if ( z_err == Z_OK ) {
1464 /* In this case Z_OK means more buffer space needed */
1465
1466 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1467 return ( -1 );
1468 }
1469 }
1470 while ( z_err == Z_OK );
1471
1472 /* If the compression state is not Z_STREAM_END, some error occurred */
1473
1474 if ( z_err == Z_STREAM_END ) {
1475
1476 /* Need to append the gzip data trailer */
1477
1478 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1479 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1480 return ( -1 );
1481 }
1482
1483 /*
1484 ** For whatever reason, the CRC and length data are pushed out
1485 ** in reverse byte order. So a memcpy can't be used here.
1486 */
1487
1488 append_reverse_ulong( buff, buff->crc );
1489 append_reverse_ulong( buff, buff->zctrl.total_in );
1490
1491 zlgth = buff->zctrl.next_out - buff->zbuff;
1492 *data_ref = (char *)buff->zbuff;
1493 }
1494
Daniel Veillard05d987b2003-10-08 11:54:57 +00001495 else {
1496 xmlChar msg[500];
1497 xmlStrPrintf(msg, 500,
1498 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1499 "Error flushing zlib buffers. Error code", z_err );
1500 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1501 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001502
1503 return ( zlgth );
1504}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001505#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001506#endif /* HAVE_ZLIB_H */
1507
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001508#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001509/**
1510 * xmlFreeHTTPWriteCtxt
1511 * @ctxt: Context to cleanup
1512 *
1513 * Free allocated memory and reclaim system resources.
1514 *
1515 * No return value.
1516 */
1517static void
1518xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1519{
1520 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001521 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001522
1523 if ( ctxt->doc_buff != NULL ) {
1524
1525#ifdef HAVE_ZLIB_H
1526 if ( ctxt->compression > 0 ) {
1527 xmlFreeZMemBuff( ctxt->doc_buff );
1528 }
1529 else
1530#endif
1531 {
1532 xmlOutputBufferClose( ctxt->doc_buff );
1533 }
1534 }
1535
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001536 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001537 return;
1538}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001539#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001540
1541
Owen Taylor3473f882001-02-23 17:55:21 +00001542/**
1543 * xmlIOHTTPMatch:
1544 * @filename: the URI for matching
1545 *
1546 * check if the URI matches an HTTP one
1547 *
1548 * Returns 1 if matches, 0 otherwise
1549 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001550int
Owen Taylor3473f882001-02-23 17:55:21 +00001551xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001552 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001553 return(1);
1554 return(0);
1555}
1556
1557/**
1558 * xmlIOHTTPOpen:
1559 * @filename: the URI for matching
1560 *
1561 * open an HTTP I/O channel
1562 *
1563 * Returns an I/O context or NULL in case of error
1564 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001565void *
Owen Taylor3473f882001-02-23 17:55:21 +00001566xmlIOHTTPOpen (const char *filename) {
1567 return(xmlNanoHTTPOpen(filename, NULL));
1568}
1569
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001570#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001571/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001572 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001573 * @post_uri: The destination URI for the document
1574 * @compression: The compression desired for the document.
1575 *
1576 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1577 * request. Non-static as is called from the output buffer creation routine.
1578 *
1579 * Returns an I/O context or NULL in case of error.
1580 */
1581
1582void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001583xmlIOHTTPOpenW(const char *post_uri, int compression)
1584{
Daniel Veillardf012a642001-07-23 19:10:52 +00001585
Daniel Veillard572577e2002-01-18 16:23:55 +00001586 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001587
Daniel Veillard572577e2002-01-18 16:23:55 +00001588 if (post_uri == NULL)
1589 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001590
Daniel Veillard572577e2002-01-18 16:23:55 +00001591 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1592 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001593 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001594 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001595 }
1596
Daniel Veillard572577e2002-01-18 16:23:55 +00001597 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001598
Daniel Veillard572577e2002-01-18 16:23:55 +00001599 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1600 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001601 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001602 xmlFreeHTTPWriteCtxt(ctxt);
1603 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001604 }
1605
1606 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001607 * ** Since the document length is required for an HTTP post,
1608 * ** need to put the document into a buffer. A memory buffer
1609 * ** is being used to avoid pushing the data to disk and back.
1610 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001611
1612#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001613 if ((compression > 0) && (compression <= 9)) {
1614
1615 ctxt->compression = compression;
1616 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1617 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001618#endif
1619 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001620 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001621
Daniel Veillard572577e2002-01-18 16:23:55 +00001622 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001623 }
1624
Daniel Veillard572577e2002-01-18 16:23:55 +00001625 if (ctxt->doc_buff == NULL) {
1626 xmlFreeHTTPWriteCtxt(ctxt);
1627 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001628 }
1629
Daniel Veillard572577e2002-01-18 16:23:55 +00001630 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001631}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001632#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001633
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001634#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001635/**
1636 * xmlIOHTTPDfltOpenW
1637 * @post_uri: The destination URI for this document.
1638 *
1639 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1640 * HTTP post command. This function should generally not be used as
1641 * the open callback is short circuited in xmlOutputBufferCreateFile.
1642 *
1643 * Returns a pointer to the new IO context.
1644 */
1645static void *
1646xmlIOHTTPDfltOpenW( const char * post_uri ) {
1647 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1648}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001649#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001650
1651/**
Owen Taylor3473f882001-02-23 17:55:21 +00001652 * xmlIOHTTPRead:
1653 * @context: the I/O context
1654 * @buffer: where to drop data
1655 * @len: number of bytes to write
1656 *
1657 * Read @len bytes to @buffer from the I/O channel.
1658 *
1659 * Returns the number of bytes written
1660 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001661int
Owen Taylor3473f882001-02-23 17:55:21 +00001662xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001663 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001664 return(xmlNanoHTTPRead(context, &buffer[0], len));
1665}
1666
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001667#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001668/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001669 * xmlIOHTTPWrite
1670 * @context: previously opened writing context
1671 * @buffer: data to output to temporary buffer
1672 * @len: bytes to output
1673 *
1674 * Collect data from memory buffer into a temporary file for later
1675 * processing.
1676 *
1677 * Returns number of bytes written.
1678 */
1679
1680static int
1681xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1682
1683 xmlIOHTTPWriteCtxtPtr ctxt = context;
1684
1685 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1686 return ( -1 );
1687
1688 if ( len > 0 ) {
1689
1690 /* Use gzwrite or fwrite as previously setup in the open call */
1691
1692#ifdef HAVE_ZLIB_H
1693 if ( ctxt->compression > 0 )
1694 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1695
1696 else
1697#endif
1698 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1699
1700 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001701 xmlChar msg[500];
1702 xmlStrPrintf(msg, 500,
1703 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001704 "Error appending to internal buffer.",
1705 "Error sending document to URI",
1706 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001707 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001708 }
1709 }
1710
1711 return ( len );
1712}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001713#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001714
1715
1716/**
Owen Taylor3473f882001-02-23 17:55:21 +00001717 * xmlIOHTTPClose:
1718 * @context: the I/O context
1719 *
1720 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001721 *
1722 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001723 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001724int
Owen Taylor3473f882001-02-23 17:55:21 +00001725xmlIOHTTPClose (void * context) {
1726 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001727 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001728}
Daniel Veillardf012a642001-07-23 19:10:52 +00001729
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001730#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001731/**
1732 * xmlIOHTTCloseWrite
1733 * @context: The I/O context
1734 * @http_mthd: The HTTP method to be used when sending the data
1735 *
1736 * Close the transmit HTTP I/O channel and actually send the data.
1737 */
1738static int
1739xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1740
1741 int close_rc = -1;
1742 int http_rtn = 0;
1743 int content_lgth = 0;
1744 xmlIOHTTPWriteCtxtPtr ctxt = context;
1745
1746 char * http_content = NULL;
1747 char * content_encoding = NULL;
1748 char * content_type = (char *) "text/xml";
1749 void * http_ctxt = NULL;
1750
1751 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1752 return ( -1 );
1753
1754 /* Retrieve the content from the appropriate buffer */
1755
1756#ifdef HAVE_ZLIB_H
1757
1758 if ( ctxt->compression > 0 ) {
1759 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1760 content_encoding = (char *) "Content-Encoding: gzip";
1761 }
1762 else
1763#endif
1764 {
1765 /* Pull the data out of the memory output buffer */
1766
1767 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1768 http_content = (char *)dctxt->buffer->content;
1769 content_lgth = dctxt->buffer->use;
1770 }
1771
1772 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001773 xmlChar msg[500];
1774 xmlStrPrintf(msg, 500,
1775 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1776 "Error retrieving content.\nUnable to",
1777 http_mthd, "data to URI", ctxt->uri );
1778 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001779 }
1780
1781 else {
1782
1783 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1784 &content_type, content_encoding,
1785 content_lgth );
1786
1787 if ( http_ctxt != NULL ) {
1788#ifdef DEBUG_HTTP
1789 /* If testing/debugging - dump reply with request content */
1790
1791 FILE * tst_file = NULL;
1792 char buffer[ 4096 ];
1793 char * dump_name = NULL;
1794 int avail;
1795
1796 xmlGenericError( xmlGenericErrorContext,
1797 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1798 http_mthd, ctxt->uri,
1799 xmlNanoHTTPReturnCode( http_ctxt ) );
1800
1801 /*
1802 ** Since either content or reply may be gzipped,
1803 ** dump them to separate files instead of the
1804 ** standard error context.
1805 */
1806
1807 dump_name = tempnam( NULL, "lxml" );
1808 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001809 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001810
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001811 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001812 if ( tst_file != NULL ) {
1813 xmlGenericError( xmlGenericErrorContext,
1814 "Transmitted content saved in file: %s\n", buffer );
1815
1816 fwrite( http_content, sizeof( char ),
1817 content_lgth, tst_file );
1818 fclose( tst_file );
1819 }
1820
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001821 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001822 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001823 if ( tst_file != NULL ) {
1824 xmlGenericError( xmlGenericErrorContext,
1825 "Reply content saved in file: %s\n", buffer );
1826
1827
1828 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1829 buffer, sizeof( buffer ) )) > 0 ) {
1830
1831 fwrite( buffer, sizeof( char ), avail, tst_file );
1832 }
1833
1834 fclose( tst_file );
1835 }
1836
1837 free( dump_name );
1838 }
1839#endif /* DEBUG_HTTP */
1840
1841 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1842 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1843 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001844 else {
1845 xmlChar msg[500];
1846 xmlStrPrintf(msg, 500,
1847 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001848 http_mthd, content_lgth,
1849 "bytes to URI", ctxt->uri,
1850 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001851 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1852 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001853
1854 xmlNanoHTTPClose( http_ctxt );
1855 xmlFree( content_type );
1856 }
1857 }
1858
1859 /* Final cleanups */
1860
1861 xmlFreeHTTPWriteCtxt( ctxt );
1862
1863 return ( close_rc );
1864}
1865
1866/**
1867 * xmlIOHTTPClosePut
1868 *
1869 * @context: The I/O context
1870 *
1871 * Close the transmit HTTP I/O channel and actually send data using a PUT
1872 * HTTP method.
1873 */
1874static int
1875xmlIOHTTPClosePut( void * ctxt ) {
1876 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1877}
1878
1879
1880/**
1881 * xmlIOHTTPClosePost
1882 *
1883 * @context: The I/O context
1884 *
1885 * Close the transmit HTTP I/O channel and actually send data using a POST
1886 * HTTP method.
1887 */
1888static int
1889xmlIOHTTPClosePost( void * ctxt ) {
1890 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1891}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001892#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001893
Owen Taylor3473f882001-02-23 17:55:21 +00001894#endif /* LIBXML_HTTP_ENABLED */
1895
1896#ifdef LIBXML_FTP_ENABLED
1897/************************************************************************
1898 * *
1899 * I/O for FTP file accesses *
1900 * *
1901 ************************************************************************/
1902/**
1903 * xmlIOFTPMatch:
1904 * @filename: the URI for matching
1905 *
1906 * check if the URI matches an FTP one
1907 *
1908 * Returns 1 if matches, 0 otherwise
1909 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001910int
Owen Taylor3473f882001-02-23 17:55:21 +00001911xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001912 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001913 return(1);
1914 return(0);
1915}
1916
1917/**
1918 * xmlIOFTPOpen:
1919 * @filename: the URI for matching
1920 *
1921 * open an FTP I/O channel
1922 *
1923 * Returns an I/O context or NULL in case of error
1924 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001925void *
Owen Taylor3473f882001-02-23 17:55:21 +00001926xmlIOFTPOpen (const char *filename) {
1927 return(xmlNanoFTPOpen(filename));
1928}
1929
1930/**
1931 * xmlIOFTPRead:
1932 * @context: the I/O context
1933 * @buffer: where to drop data
1934 * @len: number of bytes to write
1935 *
1936 * Read @len bytes to @buffer from the I/O channel.
1937 *
1938 * Returns the number of bytes written
1939 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001940int
Owen Taylor3473f882001-02-23 17:55:21 +00001941xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001942 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001943 return(xmlNanoFTPRead(context, &buffer[0], len));
1944}
1945
1946/**
1947 * xmlIOFTPClose:
1948 * @context: the I/O context
1949 *
1950 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001951 *
1952 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001953 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001954int
Owen Taylor3473f882001-02-23 17:55:21 +00001955xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001956 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001957}
1958#endif /* LIBXML_FTP_ENABLED */
1959
1960
1961/**
1962 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001963 * @matchFunc: the xmlInputMatchCallback
1964 * @openFunc: the xmlInputOpenCallback
1965 * @readFunc: the xmlInputReadCallback
1966 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001967 *
1968 * Register a new set of I/O callback for handling parser input.
1969 *
1970 * Returns the registered handler number or -1 in case of error
1971 */
1972int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001973xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1974 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1975 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001976 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1977 return(-1);
1978 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001979 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1980 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1981 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1982 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001983 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001984 return(xmlInputCallbackNr++);
1985}
1986
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001987#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001988/**
1989 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001990 * @matchFunc: the xmlOutputMatchCallback
1991 * @openFunc: the xmlOutputOpenCallback
1992 * @writeFunc: the xmlOutputWriteCallback
1993 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001994 *
1995 * Register a new set of I/O callback for handling output.
1996 *
1997 * Returns the registered handler number or -1 in case of error
1998 */
1999int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002000xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2001 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2002 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002003 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
2004 return(-1);
2005 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002006 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2007 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2008 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2009 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002010 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002011 return(xmlOutputCallbackNr++);
2012}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002013#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002014
2015/**
2016 * xmlRegisterDefaultInputCallbacks:
2017 *
2018 * Registers the default compiled-in I/O handlers.
2019 */
2020void
Owen Taylor3473f882001-02-23 17:55:21 +00002021xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002022(void) {
2023 if (xmlInputCallbackInitialized)
2024 return;
2025
2026 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2027 xmlFileRead, xmlFileClose);
2028#ifdef HAVE_ZLIB_H
2029 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2030 xmlGzfileRead, xmlGzfileClose);
2031#endif /* HAVE_ZLIB_H */
2032
2033#ifdef LIBXML_HTTP_ENABLED
2034 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2035 xmlIOHTTPRead, xmlIOHTTPClose);
2036#endif /* LIBXML_HTTP_ENABLED */
2037
2038#ifdef LIBXML_FTP_ENABLED
2039 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2040 xmlIOFTPRead, xmlIOFTPClose);
2041#endif /* LIBXML_FTP_ENABLED */
2042 xmlInputCallbackInitialized = 1;
2043}
2044
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002045#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002046/**
2047 * xmlRegisterDefaultOutputCallbacks:
2048 *
2049 * Registers the default compiled-in I/O handlers.
2050 */
2051void
Owen Taylor3473f882001-02-23 17:55:21 +00002052xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002053(void) {
2054 if (xmlOutputCallbackInitialized)
2055 return;
2056
2057 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2058 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002059
2060#ifdef LIBXML_HTTP_ENABLED
2061 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2062 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2063#endif
2064
Owen Taylor3473f882001-02-23 17:55:21 +00002065/*********************************
2066 No way a-priori to distinguish between gzipped files from
2067 uncompressed ones except opening if existing then closing
2068 and saving with same compression ratio ... a pain.
2069
2070#ifdef HAVE_ZLIB_H
2071 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2072 xmlGzfileWrite, xmlGzfileClose);
2073#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002074
2075 Nor FTP PUT ....
2076#ifdef LIBXML_FTP_ENABLED
2077 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2078 xmlIOFTPWrite, xmlIOFTPClose);
2079#endif
2080 **********************************/
2081 xmlOutputCallbackInitialized = 1;
2082}
2083
Daniel Veillardf012a642001-07-23 19:10:52 +00002084#ifdef LIBXML_HTTP_ENABLED
2085/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002086 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002087 *
2088 * By default, libxml submits HTTP output requests using the "PUT" method.
2089 * Calling this method changes the HTTP output method to use the "POST"
2090 * method instead.
2091 *
2092 */
2093void
2094xmlRegisterHTTPPostCallbacks( void ) {
2095
2096 /* Register defaults if not done previously */
2097
2098 if ( xmlOutputCallbackInitialized == 0 )
2099 xmlRegisterDefaultOutputCallbacks( );
2100
2101 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2102 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2103 return;
2104}
2105#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002106#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002107
Owen Taylor3473f882001-02-23 17:55:21 +00002108/**
2109 * xmlAllocParserInputBuffer:
2110 * @enc: the charset encoding if known
2111 *
2112 * Create a buffered parser input for progressive parsing
2113 *
2114 * Returns the new parser input or NULL
2115 */
2116xmlParserInputBufferPtr
2117xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2118 xmlParserInputBufferPtr ret;
2119
2120 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2121 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002122 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002123 return(NULL);
2124 }
2125 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002126 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002127 if (ret->buffer == NULL) {
2128 xmlFree(ret);
2129 return(NULL);
2130 }
2131 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2132 ret->encoder = xmlGetCharEncodingHandler(enc);
2133 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002134 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002135 else
2136 ret->raw = NULL;
2137 ret->readcallback = NULL;
2138 ret->closecallback = NULL;
2139 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002140 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002141 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002142
2143 return(ret);
2144}
2145
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002146#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002147/**
2148 * xmlAllocOutputBuffer:
2149 * @encoder: the encoding converter or NULL
2150 *
2151 * Create a buffered parser output
2152 *
2153 * Returns the new parser output or NULL
2154 */
2155xmlOutputBufferPtr
2156xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2157 xmlOutputBufferPtr ret;
2158
2159 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2160 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002161 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002162 return(NULL);
2163 }
2164 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2165 ret->buffer = xmlBufferCreate();
2166 if (ret->buffer == NULL) {
2167 xmlFree(ret);
2168 return(NULL);
2169 }
2170 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2171 ret->encoder = encoder;
2172 if (encoder != NULL) {
2173 ret->conv = xmlBufferCreateSize(4000);
2174 /*
2175 * This call is designed to initiate the encoder state
2176 */
2177 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2178 } else
2179 ret->conv = NULL;
2180 ret->writecallback = NULL;
2181 ret->closecallback = NULL;
2182 ret->context = NULL;
2183 ret->written = 0;
2184
2185 return(ret);
2186}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002187#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002188
2189/**
2190 * xmlFreeParserInputBuffer:
2191 * @in: a buffered parser input
2192 *
2193 * Free up the memory used by a buffered parser input
2194 */
2195void
2196xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002197 if (in == NULL) return;
2198
Owen Taylor3473f882001-02-23 17:55:21 +00002199 if (in->raw) {
2200 xmlBufferFree(in->raw);
2201 in->raw = NULL;
2202 }
2203 if (in->encoder != NULL) {
2204 xmlCharEncCloseFunc(in->encoder);
2205 }
2206 if (in->closecallback != NULL) {
2207 in->closecallback(in->context);
2208 }
2209 if (in->buffer != NULL) {
2210 xmlBufferFree(in->buffer);
2211 in->buffer = NULL;
2212 }
2213
Owen Taylor3473f882001-02-23 17:55:21 +00002214 xmlFree(in);
2215}
2216
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002217#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002218/**
2219 * xmlOutputBufferClose:
2220 * @out: a buffered output
2221 *
2222 * flushes and close the output I/O channel
2223 * and free up all the associated resources
2224 *
2225 * Returns the number of byte written or -1 in case of error.
2226 */
2227int
Daniel Veillard828ce832003-10-08 19:19:10 +00002228xmlOutputBufferClose(xmlOutputBufferPtr out)
2229{
Owen Taylor3473f882001-02-23 17:55:21 +00002230 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002231 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002232
2233 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002234 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002235 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002236 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002237 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002238 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002239 }
2240 written = out->written;
2241 if (out->conv) {
2242 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002243 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002244 }
2245 if (out->encoder != NULL) {
2246 xmlCharEncCloseFunc(out->encoder);
2247 }
2248 if (out->buffer != NULL) {
2249 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002250 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002251 }
2252
Daniel Veillard828ce832003-10-08 19:19:10 +00002253 if (out->error)
2254 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002255 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002256 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002257}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002258#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002259
Daniel Veillard1b243b42004-06-08 10:16:42 +00002260xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002261__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002262 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002263 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002264 void *context = NULL;
2265
2266 if (xmlInputCallbackInitialized == 0)
2267 xmlRegisterDefaultInputCallbacks();
2268
2269 if (URI == NULL) return(NULL);
2270
2271 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002272 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002273 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002274 */
2275 if (context == NULL) {
2276 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2277 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2278 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002279 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002280 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002281 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002282 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002283 }
Owen Taylor3473f882001-02-23 17:55:21 +00002284 }
2285 }
2286 if (context == NULL) {
2287 return(NULL);
2288 }
2289
2290 /*
2291 * Allocate the Input buffer front-end.
2292 */
2293 ret = xmlAllocParserInputBuffer(enc);
2294 if (ret != NULL) {
2295 ret->context = context;
2296 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2297 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002298#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002299 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2300 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002301 if (((z_stream *)context)->avail_in > 4) {
2302 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002303 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002304 if (gzread(context, buff4, 4) == 4) {
2305 if (strncmp(buff4, cptr, 4) == 0)
2306 ret->compressed = 0;
2307 else
2308 ret->compressed = 1;
2309 gzrewind(context);
2310 }
2311 }
2312 }
2313#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002314 }
William M. Brack42331a92004-07-29 07:07:16 +00002315 else
2316 xmlInputCallbackTable[i].closecallback (context);
2317
Owen Taylor3473f882001-02-23 17:55:21 +00002318 return(ret);
2319}
2320
2321/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002322 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002323 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002324 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002325 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002326 * Create a buffered parser input for the progressive parsing of a file
2327 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002328 * Automatic support for ZLIB/Compress compressed document is provided
2329 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002330 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002331 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002332 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002333 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002334xmlParserInputBufferPtr
2335xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2336 if ((xmlParserInputBufferCreateFilenameValue)) {
2337 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2338 }
2339 return __xmlParserInputBufferCreateFilename(URI, enc);
2340}
2341
2342#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002343xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002344__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002345 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002346 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002347 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002348 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002349 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002350 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002351 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002352#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002353 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002354#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002355
Owen Taylor3473f882001-02-23 17:55:21 +00002356 if (xmlOutputCallbackInitialized == 0)
2357 xmlRegisterDefaultOutputCallbacks();
2358
2359 if (URI == NULL) return(NULL);
2360
Daniel Veillard966a31e2004-05-09 02:58:44 +00002361 puri = xmlParseURI(URI);
2362 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002363#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002364 if ((puri->scheme != NULL) &&
2365 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002366 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002367#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002368 /*
2369 * try to limit the damages of the URI unescaping code.
2370 */
2371 if (puri->scheme != NULL)
2372 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2373 xmlFreeURI(puri);
2374 }
Owen Taylor3473f882001-02-23 17:55:21 +00002375
2376 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002377 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002378 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002379 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002380 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002381 if (unescaped != NULL) {
2382#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002383 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002384 context = xmlGzfileOpenW(unescaped, compression);
2385 if (context != NULL) {
2386 ret = xmlAllocOutputBuffer(encoder);
2387 if (ret != NULL) {
2388 ret->context = context;
2389 ret->writecallback = xmlGzfileWrite;
2390 ret->closecallback = xmlGzfileClose;
2391 }
2392 xmlFree(unescaped);
2393 return(ret);
2394 }
2395 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002396#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002397 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2398 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2399 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2400#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2401 /* Need to pass compression parameter into HTTP open calls */
2402 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2403 context = xmlIOHTTPOpenW(unescaped, compression);
2404 else
2405#endif
2406 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2407 if (context != NULL)
2408 break;
2409 }
2410 }
2411 xmlFree(unescaped);
2412 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002413
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002414 /*
2415 * If this failed try with a non-escaped URI this may be a strange
2416 * filename
2417 */
2418 if (context == NULL) {
2419#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002420 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002421 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002422 if (context != NULL) {
2423 ret = xmlAllocOutputBuffer(encoder);
2424 if (ret != NULL) {
2425 ret->context = context;
2426 ret->writecallback = xmlGzfileWrite;
2427 ret->closecallback = xmlGzfileClose;
2428 }
2429 return(ret);
2430 }
2431 }
2432#endif
2433 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2434 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002435 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002436#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2437 /* Need to pass compression parameter into HTTP open calls */
2438 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2439 context = xmlIOHTTPOpenW(URI, compression);
2440 else
2441#endif
2442 context = xmlOutputCallbackTable[i].opencallback(URI);
2443 if (context != NULL)
2444 break;
2445 }
Owen Taylor3473f882001-02-23 17:55:21 +00002446 }
2447 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002448
Owen Taylor3473f882001-02-23 17:55:21 +00002449 if (context == NULL) {
2450 return(NULL);
2451 }
2452
2453 /*
2454 * Allocate the Output buffer front-end.
2455 */
2456 ret = xmlAllocOutputBuffer(encoder);
2457 if (ret != NULL) {
2458 ret->context = context;
2459 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2460 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2461 }
2462 return(ret);
2463}
Daniel Veillard0335a842004-06-02 16:18:40 +00002464
2465/**
2466 * xmlOutputBufferCreateFilename:
2467 * @URI: a C string containing the URI or filename
2468 * @encoder: the encoding converter or NULL
2469 * @compression: the compression ration (0 none, 9 max).
2470 *
2471 * Create a buffered output for the progressive saving of a file
2472 * If filename is "-' then we use stdout as the output.
2473 * Automatic support for ZLIB/Compress compressed document is provided
2474 * by default if found at compile-time.
2475 * TODO: currently if compression is set, the library only support
2476 * writing to a local file.
2477 *
2478 * Returns the new output or NULL
2479 */
2480xmlOutputBufferPtr
2481xmlOutputBufferCreateFilename(const char *URI,
2482 xmlCharEncodingHandlerPtr encoder,
2483 int compression ATTRIBUTE_UNUSED) {
2484 if ((xmlOutputBufferCreateFilenameValue)) {
2485 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2486 }
2487 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2488}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002489#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002490
2491/**
2492 * xmlParserInputBufferCreateFile:
2493 * @file: a FILE*
2494 * @enc: the charset encoding if known
2495 *
2496 * Create a buffered parser input for the progressive parsing of a FILE *
2497 * buffered C I/O
2498 *
2499 * Returns the new parser input or NULL
2500 */
2501xmlParserInputBufferPtr
2502xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2503 xmlParserInputBufferPtr ret;
2504
2505 if (xmlInputCallbackInitialized == 0)
2506 xmlRegisterDefaultInputCallbacks();
2507
2508 if (file == NULL) return(NULL);
2509
2510 ret = xmlAllocParserInputBuffer(enc);
2511 if (ret != NULL) {
2512 ret->context = file;
2513 ret->readcallback = xmlFileRead;
2514 ret->closecallback = xmlFileFlush;
2515 }
2516
2517 return(ret);
2518}
2519
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002520#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002521/**
2522 * xmlOutputBufferCreateFile:
2523 * @file: a FILE*
2524 * @encoder: the encoding converter or NULL
2525 *
2526 * Create a buffered output for the progressive saving to a FILE *
2527 * buffered C I/O
2528 *
2529 * Returns the new parser output or NULL
2530 */
2531xmlOutputBufferPtr
2532xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2533 xmlOutputBufferPtr ret;
2534
2535 if (xmlOutputCallbackInitialized == 0)
2536 xmlRegisterDefaultOutputCallbacks();
2537
2538 if (file == NULL) return(NULL);
2539
2540 ret = xmlAllocOutputBuffer(encoder);
2541 if (ret != NULL) {
2542 ret->context = file;
2543 ret->writecallback = xmlFileWrite;
2544 ret->closecallback = xmlFileFlush;
2545 }
2546
2547 return(ret);
2548}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002549
2550/**
2551 * xmlOutputBufferCreateBuffer:
2552 * @buffer: a xmlBufferPtr
2553 * @encoder: the encoding converter or NULL
2554 *
2555 * Create a buffered output for the progressive saving to a xmlBuffer
2556 *
2557 * Returns the new parser output or NULL
2558 */
2559xmlOutputBufferPtr
2560xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2561 xmlCharEncodingHandlerPtr encoder) {
2562 xmlOutputBufferPtr ret;
2563
2564 if (buffer == NULL) return(NULL);
2565
Rob Richardsa44f2342005-11-09 18:03:45 +00002566 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2567 xmlBufferWrite,
2568 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002569 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002570
2571 return(ret);
2572}
2573
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002574#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002575
2576/**
2577 * xmlParserInputBufferCreateFd:
2578 * @fd: a file descriptor number
2579 * @enc: the charset encoding if known
2580 *
2581 * Create a buffered parser input for the progressive parsing for the input
2582 * from a file descriptor
2583 *
2584 * Returns the new parser input or NULL
2585 */
2586xmlParserInputBufferPtr
2587xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2588 xmlParserInputBufferPtr ret;
2589
2590 if (fd < 0) return(NULL);
2591
2592 ret = xmlAllocParserInputBuffer(enc);
2593 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002594 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002595 ret->readcallback = xmlFdRead;
2596 ret->closecallback = xmlFdClose;
2597 }
2598
2599 return(ret);
2600}
2601
2602/**
2603 * xmlParserInputBufferCreateMem:
2604 * @mem: the memory input
2605 * @size: the length of the memory block
2606 * @enc: the charset encoding if known
2607 *
2608 * Create a buffered parser input for the progressive parsing for the input
2609 * from a memory area.
2610 *
2611 * Returns the new parser input or NULL
2612 */
2613xmlParserInputBufferPtr
2614xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2615 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002616 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002617
2618 if (size <= 0) return(NULL);
2619 if (mem == NULL) return(NULL);
2620
2621 ret = xmlAllocParserInputBuffer(enc);
2622 if (ret != NULL) {
2623 ret->context = (void *) mem;
2624 ret->readcallback = (xmlInputReadCallback) xmlNop;
2625 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002626 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2627 if (errcode != 0) {
2628 xmlFree(ret);
2629 return(NULL);
2630 }
Owen Taylor3473f882001-02-23 17:55:21 +00002631 }
2632
2633 return(ret);
2634}
2635
2636/**
Daniel Veillard53350552003-09-18 13:35:51 +00002637 * xmlParserInputBufferCreateStatic:
2638 * @mem: the memory input
2639 * @size: the length of the memory block
2640 * @enc: the charset encoding if known
2641 *
2642 * Create a buffered parser input for the progressive parsing for the input
2643 * from an immutable memory area. This will not copy the memory area to
2644 * the buffer, but the memory is expected to be available until the end of
2645 * the parsing, this is useful for example when using mmap'ed file.
2646 *
2647 * Returns the new parser input or NULL
2648 */
2649xmlParserInputBufferPtr
2650xmlParserInputBufferCreateStatic(const char *mem, int size,
2651 xmlCharEncoding enc) {
2652 xmlParserInputBufferPtr ret;
2653
2654 if (size <= 0) return(NULL);
2655 if (mem == NULL) return(NULL);
2656
2657 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2658 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002659 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002660 return(NULL);
2661 }
2662 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002663 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002664 if (ret->buffer == NULL) {
2665 xmlFree(ret);
2666 return(NULL);
2667 }
2668 ret->encoder = xmlGetCharEncodingHandler(enc);
2669 if (ret->encoder != NULL)
2670 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2671 else
2672 ret->raw = NULL;
2673 ret->compressed = -1;
2674 ret->context = (void *) mem;
2675 ret->readcallback = NULL;
2676 ret->closecallback = NULL;
2677
2678 return(ret);
2679}
2680
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002681#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002682/**
Owen Taylor3473f882001-02-23 17:55:21 +00002683 * xmlOutputBufferCreateFd:
2684 * @fd: a file descriptor number
2685 * @encoder: the encoding converter or NULL
2686 *
2687 * Create a buffered output for the progressive saving
2688 * to a file descriptor
2689 *
2690 * Returns the new parser output or NULL
2691 */
2692xmlOutputBufferPtr
2693xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2694 xmlOutputBufferPtr ret;
2695
2696 if (fd < 0) return(NULL);
2697
2698 ret = xmlAllocOutputBuffer(encoder);
2699 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002700 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002701 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002702 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002703 }
2704
2705 return(ret);
2706}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002707#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002708
2709/**
2710 * xmlParserInputBufferCreateIO:
2711 * @ioread: an I/O read function
2712 * @ioclose: an I/O close function
2713 * @ioctx: an I/O handler
2714 * @enc: the charset encoding if known
2715 *
2716 * Create a buffered parser input for the progressive parsing for the input
2717 * from an I/O handler
2718 *
2719 * Returns the new parser input or NULL
2720 */
2721xmlParserInputBufferPtr
2722xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2723 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2724 xmlParserInputBufferPtr ret;
2725
2726 if (ioread == NULL) return(NULL);
2727
2728 ret = xmlAllocParserInputBuffer(enc);
2729 if (ret != NULL) {
2730 ret->context = (void *) ioctx;
2731 ret->readcallback = ioread;
2732 ret->closecallback = ioclose;
2733 }
2734
2735 return(ret);
2736}
2737
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002738#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002739/**
2740 * xmlOutputBufferCreateIO:
2741 * @iowrite: an I/O write function
2742 * @ioclose: an I/O close function
2743 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002744 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002745 *
2746 * Create a buffered output for the progressive saving
2747 * to an I/O handler
2748 *
2749 * Returns the new parser output or NULL
2750 */
2751xmlOutputBufferPtr
2752xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2753 xmlOutputCloseCallback ioclose, void *ioctx,
2754 xmlCharEncodingHandlerPtr encoder) {
2755 xmlOutputBufferPtr ret;
2756
2757 if (iowrite == NULL) return(NULL);
2758
2759 ret = xmlAllocOutputBuffer(encoder);
2760 if (ret != NULL) {
2761 ret->context = (void *) ioctx;
2762 ret->writecallback = iowrite;
2763 ret->closecallback = ioclose;
2764 }
2765
2766 return(ret);
2767}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002768#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002769
2770/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002771 * xmlParserInputBufferCreateFilenameDefault:
2772 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2773 *
2774 * Registers a callback for URI input file handling
2775 *
2776 * Returns the old value of the registration function
2777 */
2778xmlParserInputBufferCreateFilenameFunc
2779xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2780{
2781 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2782 if (old == NULL) {
2783 old = __xmlParserInputBufferCreateFilename;
2784 }
2785
2786 xmlParserInputBufferCreateFilenameValue = func;
2787 return(old);
2788}
2789
2790/**
2791 * xmlOutputBufferCreateFilenameDefault:
2792 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2793 *
2794 * Registers a callback for URI output file handling
2795 *
2796 * Returns the old value of the registration function
2797 */
2798xmlOutputBufferCreateFilenameFunc
2799xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2800{
2801 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2802#ifdef LIBXML_OUTPUT_ENABLED
2803 if (old == NULL) {
2804 old = __xmlOutputBufferCreateFilename;
2805 }
2806#endif
2807 xmlOutputBufferCreateFilenameValue = func;
2808 return(old);
2809}
2810
2811/**
Owen Taylor3473f882001-02-23 17:55:21 +00002812 * xmlParserInputBufferPush:
2813 * @in: a buffered parser input
2814 * @len: the size in bytes of the array.
2815 * @buf: an char array
2816 *
2817 * Push the content of the arry in the input buffer
2818 * This routine handle the I18N transcoding to internal UTF-8
2819 * This is used when operating the parser in progressive (push) mode.
2820 *
2821 * Returns the number of chars read and stored in the buffer, or -1
2822 * in case of error.
2823 */
2824int
2825xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2826 int len, const char *buf) {
2827 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002828 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002829
2830 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002831 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002832 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002833 unsigned int use;
2834
Owen Taylor3473f882001-02-23 17:55:21 +00002835 /*
2836 * Store the data in the incoming raw buffer
2837 */
2838 if (in->raw == NULL) {
2839 in->raw = xmlBufferCreate();
2840 }
William M. Bracka3215c72004-07-31 16:24:01 +00002841 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2842 if (ret != 0)
2843 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002844
2845 /*
2846 * convert as much as possible to the parser reading buffer.
2847 */
Daniel Veillard36711902004-02-11 13:25:26 +00002848 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002849 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2850 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002851 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002852 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002853 return(-1);
2854 }
Daniel Veillard36711902004-02-11 13:25:26 +00002855 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002856 } else {
2857 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002858 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2859 if (ret != 0)
2860 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002861 }
2862#ifdef DEBUG_INPUT
2863 xmlGenericError(xmlGenericErrorContext,
2864 "I/O: pushed %d chars, buffer %d/%d\n",
2865 nbchars, in->buffer->use, in->buffer->size);
2866#endif
2867 return(nbchars);
2868}
2869
2870/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002871 * endOfInput:
2872 *
2873 * When reading from an Input channel indicated end of file or error
2874 * don't reread from it again.
2875 */
2876static int
2877endOfInput (void * context ATTRIBUTE_UNUSED,
2878 char * buffer ATTRIBUTE_UNUSED,
2879 int len ATTRIBUTE_UNUSED) {
2880 return(0);
2881}
2882
2883/**
Owen Taylor3473f882001-02-23 17:55:21 +00002884 * xmlParserInputBufferGrow:
2885 * @in: a buffered parser input
2886 * @len: indicative value of the amount of chars to read
2887 *
2888 * Grow up the content of the input buffer, the old data are preserved
2889 * This routine handle the I18N transcoding to internal UTF-8
2890 * This routine is used when operating the parser in normal (pull) mode
2891 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002892 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002893 * onto in->buffer or in->raw
2894 *
2895 * Returns the number of chars read and stored in the buffer, or -1
2896 * in case of error.
2897 */
2898int
2899xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2900 char *buffer = NULL;
2901 int res = 0;
2902 int nbchars = 0;
2903 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002904 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002905
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002906 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002907 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002908 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002909
Owen Taylor3473f882001-02-23 17:55:21 +00002910 buffree = in->buffer->size - in->buffer->use;
2911 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002912 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002913 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002914 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002915 }
Owen Taylor3473f882001-02-23 17:55:21 +00002916
Daniel Veillarde5354492002-05-16 08:43:22 +00002917 needSize = in->buffer->use + len + 1;
2918 if (needSize > in->buffer->size){
2919 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002920 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002921 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002922 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002923 }
Owen Taylor3473f882001-02-23 17:55:21 +00002924 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002925 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002926
2927 /*
2928 * Call the read method for this I/O type.
2929 */
2930 if (in->readcallback != NULL) {
2931 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002932 if (res <= 0)
2933 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002934 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002935 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002936 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002937 return(-1);
2938 }
2939 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002940 return(-1);
2941 }
2942 len = res;
2943 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002944 unsigned int use;
2945
Owen Taylor3473f882001-02-23 17:55:21 +00002946 /*
2947 * Store the data in the incoming raw buffer
2948 */
2949 if (in->raw == NULL) {
2950 in->raw = xmlBufferCreate();
2951 }
William M. Bracka3215c72004-07-31 16:24:01 +00002952 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2953 if (res != 0)
2954 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002955
2956 /*
2957 * convert as much as possible to the parser reading buffer.
2958 */
Daniel Veillard36711902004-02-11 13:25:26 +00002959 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002960 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2961 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002962 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002963 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002964 return(-1);
2965 }
Daniel Veillard36711902004-02-11 13:25:26 +00002966 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002967 } else {
2968 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002969 in->buffer->use += nbchars;
2970 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002971 }
2972#ifdef DEBUG_INPUT
2973 xmlGenericError(xmlGenericErrorContext,
2974 "I/O: read %d chars, buffer %d/%d\n",
2975 nbchars, in->buffer->use, in->buffer->size);
2976#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002977 return(nbchars);
2978}
2979
2980/**
2981 * xmlParserInputBufferRead:
2982 * @in: a buffered parser input
2983 * @len: indicative value of the amount of chars to read
2984 *
2985 * Refresh the content of the input buffer, the old data are considered
2986 * consumed
2987 * This routine handle the I18N transcoding to internal UTF-8
2988 *
2989 * Returns the number of chars read and stored in the buffer, or -1
2990 * in case of error.
2991 */
2992int
2993xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002994 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002995 if (in->readcallback != NULL)
2996 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002997 else if ((in->buffer != NULL) &&
2998 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2999 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003000 else
3001 return(-1);
3002}
3003
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003004#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003005/**
3006 * xmlOutputBufferWrite:
3007 * @out: a buffered parser output
3008 * @len: the size in bytes of the array.
3009 * @buf: an char array
3010 *
3011 * Write the content of the array in the output I/O buffer
3012 * This routine handle the I18N transcoding from internal UTF-8
3013 * The buffer is lossless, i.e. will store in case of partial
3014 * or delayed writes.
3015 *
3016 * Returns the number of chars immediately written, or -1
3017 * in case of error.
3018 */
3019int
3020xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3021 int nbchars = 0; /* number of chars to output to I/O */
3022 int ret; /* return from function call */
3023 int written = 0; /* number of char written to I/O so far */
3024 int chunk; /* number of byte curreent processed from buf */
3025
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003026 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003027 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003028 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003029
3030 do {
3031 chunk = len;
3032 if (chunk > 4 * MINLEN)
3033 chunk = 4 * MINLEN;
3034
3035 /*
3036 * first handle encoding stuff.
3037 */
3038 if (out->encoder != NULL) {
3039 /*
3040 * Store the data in the incoming raw buffer
3041 */
3042 if (out->conv == NULL) {
3043 out->conv = xmlBufferCreate();
3044 }
William M. Bracka3215c72004-07-31 16:24:01 +00003045 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3046 if (ret != 0)
3047 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003048
3049 if ((out->buffer->use < MINLEN) && (chunk == len))
3050 goto done;
3051
3052 /*
3053 * convert as much as possible to the parser reading buffer.
3054 */
3055 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003056 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003057 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003058 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003059 return(-1);
3060 }
3061 nbchars = out->conv->use;
3062 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003063 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3064 if (ret != 0)
3065 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003066 nbchars = out->buffer->use;
3067 }
3068 buf += chunk;
3069 len -= chunk;
3070
3071 if ((nbchars < MINLEN) && (len <= 0))
3072 goto done;
3073
3074 if (out->writecallback) {
3075 /*
3076 * second write the stuff to the I/O channel
3077 */
3078 if (out->encoder != NULL) {
3079 ret = out->writecallback(out->context,
3080 (const char *)out->conv->content, nbchars);
3081 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003082 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003083 } else {
3084 ret = out->writecallback(out->context,
3085 (const char *)out->buffer->content, nbchars);
3086 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003087 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003088 }
3089 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003090 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003091 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003092 return(ret);
3093 }
3094 out->written += ret;
3095 }
3096 written += nbchars;
3097 } while (len > 0);
3098
3099done:
3100#ifdef DEBUG_INPUT
3101 xmlGenericError(xmlGenericErrorContext,
3102 "I/O: wrote %d chars\n", written);
3103#endif
3104 return(written);
3105}
3106
3107/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003108 * xmlEscapeContent:
3109 * @out: a pointer to an array of bytes to store the result
3110 * @outlen: the length of @out
3111 * @in: a pointer to an array of unescaped UTF-8 bytes
3112 * @inlen: the length of @in
3113 *
3114 * Take a block of UTF-8 chars in and escape them.
3115 * Returns 0 if success, or -1 otherwise
3116 * The value of @inlen after return is the number of octets consumed
3117 * if the return value is positive, else unpredictable.
3118 * The value of @outlen after return is the number of octets consumed.
3119 */
3120static int
3121xmlEscapeContent(unsigned char* out, int *outlen,
3122 const xmlChar* in, int *inlen) {
3123 unsigned char* outstart = out;
3124 const unsigned char* base = in;
3125 unsigned char* outend = out + *outlen;
3126 const unsigned char* inend;
3127
3128 inend = in + (*inlen);
3129
3130 while ((in < inend) && (out < outend)) {
3131 if (*in == '<') {
3132 if (outend - out < 4) break;
3133 *out++ = '&';
3134 *out++ = 'l';
3135 *out++ = 't';
3136 *out++ = ';';
3137 } else if (*in == '>') {
3138 if (outend - out < 4) break;
3139 *out++ = '&';
3140 *out++ = 'g';
3141 *out++ = 't';
3142 *out++ = ';';
3143 } else if (*in == '&') {
3144 if (outend - out < 5) break;
3145 *out++ = '&';
3146 *out++ = 'a';
3147 *out++ = 'm';
3148 *out++ = 'p';
3149 *out++ = ';';
3150 } else if (*in == '\r') {
3151 if (outend - out < 5) break;
3152 *out++ = '&';
3153 *out++ = '#';
3154 *out++ = '1';
3155 *out++ = '3';
3156 *out++ = ';';
3157 } else {
3158 *out++ = (unsigned char) *in;
3159 }
3160 ++in;
3161 }
3162 *outlen = out - outstart;
3163 *inlen = in - base;
3164 return(0);
3165}
3166
3167/**
3168 * xmlOutputBufferWriteEscape:
3169 * @out: a buffered parser output
3170 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003171 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003172 *
3173 * Write the content of the string in the output I/O buffer
3174 * This routine escapes the caracters and then handle the I18N
3175 * transcoding from internal UTF-8
3176 * The buffer is lossless, i.e. will store in case of partial
3177 * or delayed writes.
3178 *
3179 * Returns the number of chars immediately written, or -1
3180 * in case of error.
3181 */
3182int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003183xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3184 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003185 int nbchars = 0; /* number of chars to output to I/O */
3186 int ret; /* return from function call */
3187 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003188 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003189 int chunk; /* number of byte currently processed from str */
3190 int len; /* number of bytes in str */
3191 int cons; /* byte from str consumed */
3192
Daniel Veillardce244ad2004-11-05 10:03:46 +00003193 if ((out == NULL) || (out->error) || (str == NULL) ||
3194 (out->buffer == NULL) ||
3195 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003196 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003197 if (len < 0) return(0);
3198 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003199 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003200
3201 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003202 oldwritten = written;
3203
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003204 /*
3205 * how many bytes to consume and how many bytes to store.
3206 */
3207 cons = len;
3208 chunk = (out->buffer->size - out->buffer->use) - 1;
3209
3210 /*
3211 * first handle encoding stuff.
3212 */
3213 if (out->encoder != NULL) {
3214 /*
3215 * Store the data in the incoming raw buffer
3216 */
3217 if (out->conv == NULL) {
3218 out->conv = xmlBufferCreate();
3219 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003220 ret = escaping(out->buffer->content + out->buffer->use ,
3221 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003222 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003223 return(-1);
3224 out->buffer->use += chunk;
3225 out->buffer->content[out->buffer->use] = 0;
3226
3227 if ((out->buffer->use < MINLEN) && (cons == len))
3228 goto done;
3229
3230 /*
3231 * convert as much as possible to the output buffer.
3232 */
3233 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3234 if ((ret < 0) && (ret != -3)) {
3235 xmlIOErr(XML_IO_ENCODER, NULL);
3236 out->error = XML_IO_ENCODER;
3237 return(-1);
3238 }
3239 nbchars = out->conv->use;
3240 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003241 ret = escaping(out->buffer->content + out->buffer->use ,
3242 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003243 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003244 return(-1);
3245 out->buffer->use += chunk;
3246 out->buffer->content[out->buffer->use] = 0;
3247 nbchars = out->buffer->use;
3248 }
3249 str += cons;
3250 len -= cons;
3251
3252 if ((nbchars < MINLEN) && (len <= 0))
3253 goto done;
3254
3255 if (out->writecallback) {
3256 /*
3257 * second write the stuff to the I/O channel
3258 */
3259 if (out->encoder != NULL) {
3260 ret = out->writecallback(out->context,
3261 (const char *)out->conv->content, nbchars);
3262 if (ret >= 0)
3263 xmlBufferShrink(out->conv, ret);
3264 } else {
3265 ret = out->writecallback(out->context,
3266 (const char *)out->buffer->content, nbchars);
3267 if (ret >= 0)
3268 xmlBufferShrink(out->buffer, ret);
3269 }
3270 if (ret < 0) {
3271 xmlIOErr(XML_IO_WRITE, NULL);
3272 out->error = XML_IO_WRITE;
3273 return(ret);
3274 }
3275 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003276 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3277 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003278 }
3279 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003280 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003281
3282done:
3283#ifdef DEBUG_INPUT
3284 xmlGenericError(xmlGenericErrorContext,
3285 "I/O: wrote %d chars\n", written);
3286#endif
3287 return(written);
3288}
3289
3290/**
Owen Taylor3473f882001-02-23 17:55:21 +00003291 * xmlOutputBufferWriteString:
3292 * @out: a buffered parser output
3293 * @str: a zero terminated C string
3294 *
3295 * Write the content of the string in the output I/O buffer
3296 * This routine handle the I18N transcoding from internal UTF-8
3297 * The buffer is lossless, i.e. will store in case of partial
3298 * or delayed writes.
3299 *
3300 * Returns the number of chars immediately written, or -1
3301 * in case of error.
3302 */
3303int
3304xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3305 int len;
3306
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003307 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003308 if (str == NULL)
3309 return(-1);
3310 len = strlen(str);
3311
3312 if (len > 0)
3313 return(xmlOutputBufferWrite(out, len, str));
3314 return(len);
3315}
3316
3317/**
3318 * xmlOutputBufferFlush:
3319 * @out: a buffered output
3320 *
3321 * flushes the output I/O channel
3322 *
3323 * Returns the number of byte written or -1 in case of error.
3324 */
3325int
3326xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3327 int nbchars = 0, ret = 0;
3328
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003329 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003330 /*
3331 * first handle encoding stuff.
3332 */
3333 if ((out->conv != NULL) && (out->encoder != NULL)) {
3334 /*
3335 * convert as much as possible to the parser reading buffer.
3336 */
3337 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3338 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003339 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003340 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003341 return(-1);
3342 }
3343 }
3344
3345 /*
3346 * second flush the stuff to the I/O channel
3347 */
3348 if ((out->conv != NULL) && (out->encoder != NULL) &&
3349 (out->writecallback != NULL)) {
3350 ret = out->writecallback(out->context,
3351 (const char *)out->conv->content, out->conv->use);
3352 if (ret >= 0)
3353 xmlBufferShrink(out->conv, ret);
3354 } else if (out->writecallback != NULL) {
3355 ret = out->writecallback(out->context,
3356 (const char *)out->buffer->content, out->buffer->use);
3357 if (ret >= 0)
3358 xmlBufferShrink(out->buffer, ret);
3359 }
3360 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003361 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003362 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003363 return(ret);
3364 }
3365 out->written += ret;
3366
3367#ifdef DEBUG_INPUT
3368 xmlGenericError(xmlGenericErrorContext,
3369 "I/O: flushed %d chars\n", ret);
3370#endif
3371 return(ret);
3372}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003373#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003374
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003375/**
Owen Taylor3473f882001-02-23 17:55:21 +00003376 * xmlParserGetDirectory:
3377 * @filename: the path to a file
3378 *
3379 * lookup the directory for that file
3380 *
3381 * Returns a new allocated string containing the directory, or NULL.
3382 */
3383char *
3384xmlParserGetDirectory(const char *filename) {
3385 char *ret = NULL;
3386 char dir[1024];
3387 char *cur;
3388 char sep = '/';
3389
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003390#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3391 return NULL;
3392#endif
3393
Owen Taylor3473f882001-02-23 17:55:21 +00003394 if (xmlInputCallbackInitialized == 0)
3395 xmlRegisterDefaultInputCallbacks();
3396
3397 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003398#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003399 sep = '\\';
3400#endif
3401
3402 strncpy(dir, filename, 1023);
3403 dir[1023] = 0;
3404 cur = &dir[strlen(dir)];
3405 while (cur > dir) {
3406 if (*cur == sep) break;
3407 cur --;
3408 }
3409 if (*cur == sep) {
3410 if (cur == dir) dir[1] = 0;
3411 else *cur = 0;
3412 ret = xmlMemStrdup(dir);
3413 } else {
3414 if (getcwd(dir, 1024) != NULL) {
3415 dir[1023] = 0;
3416 ret = xmlMemStrdup(dir);
3417 }
3418 }
3419 return(ret);
3420}
3421
3422/****************************************************************
3423 * *
3424 * External entities loading *
3425 * *
3426 ****************************************************************/
3427
Daniel Veillarda840b692003-10-19 13:35:37 +00003428/**
3429 * xmlCheckHTTPInput:
3430 * @ctxt: an XML parser context
3431 * @ret: an XML parser input
3432 *
3433 * Check an input in case it was created from an HTTP stream, in that
3434 * case it will handle encoding and update of the base URL in case of
3435 * redirection. It also checks for HTTP errors in which case the input
3436 * is cleanly freed up and an appropriate error is raised in context
3437 *
3438 * Returns the input or NULL in case of HTTP error.
3439 */
3440xmlParserInputPtr
3441xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3442#ifdef LIBXML_HTTP_ENABLED
3443 if ((ret != NULL) && (ret->buf != NULL) &&
3444 (ret->buf->readcallback == xmlIOHTTPRead) &&
3445 (ret->buf->context != NULL)) {
3446 const char *encoding;
3447 const char *redir;
3448 const char *mime;
3449 int code;
3450
3451 code = xmlNanoHTTPReturnCode(ret->buf->context);
3452 if (code >= 400) {
3453 /* fatal error */
3454 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003455 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003456 (const char *) ret->filename);
3457 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003458 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003459 xmlFreeInputStream(ret);
3460 ret = NULL;
3461 } else {
3462
3463 mime = xmlNanoHTTPMimeType(ret->buf->context);
3464 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3465 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3466 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3467 if (encoding != NULL) {
3468 xmlCharEncodingHandlerPtr handler;
3469
3470 handler = xmlFindCharEncodingHandler(encoding);
3471 if (handler != NULL) {
3472 xmlSwitchInputEncoding(ctxt, ret, handler);
3473 } else {
3474 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3475 "Unknown encoding %s",
3476 BAD_CAST encoding, NULL);
3477 }
3478 if (ret->encoding == NULL)
3479 ret->encoding = xmlStrdup(BAD_CAST encoding);
3480 }
3481#if 0
3482 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3483#endif
3484 }
3485 redir = xmlNanoHTTPRedir(ret->buf->context);
3486 if (redir != NULL) {
3487 if (ret->filename != NULL)
3488 xmlFree((xmlChar *) ret->filename);
3489 if (ret->directory != NULL) {
3490 xmlFree((xmlChar *) ret->directory);
3491 ret->directory = NULL;
3492 }
3493 ret->filename =
3494 (char *) xmlStrdup((const xmlChar *) redir);
3495 }
3496 }
3497 }
3498#endif
3499 return(ret);
3500}
3501
Daniel Veillard561b7f82002-03-20 21:55:57 +00003502static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003503#ifdef HAVE_STAT
3504 int ret;
3505 struct stat info;
3506 const char *path;
3507
3508 if (URL == NULL)
3509 return(0);
3510
Daniel Veillardf4862f02002-09-10 11:13:43 +00003511 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003512#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003513 path = &URL[17];
3514#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003515 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003516#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003517 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003518#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003519 path = &URL[8];
3520#else
3521 path = &URL[7];
3522#endif
3523 } else
3524 path = URL;
3525 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003526 if (ret == 0)
3527 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003528#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003529 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003530}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003531
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003532/**
Owen Taylor3473f882001-02-23 17:55:21 +00003533 * xmlDefaultExternalEntityLoader:
3534 * @URL: the URL for the entity to load
3535 * @ID: the System ID for the entity to load
3536 * @ctxt: the context in which the entity is called or NULL
3537 *
3538 * By default we don't load external entitites, yet.
3539 *
3540 * Returns a new allocated xmlParserInputPtr, or NULL.
3541 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003542static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003543xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003544 xmlParserCtxtPtr ctxt)
3545{
Owen Taylor3473f882001-02-23 17:55:21 +00003546 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003547 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003548
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003549#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003550 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003551#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003552
3553#ifdef DEBUG_EXTERNAL_ENTITIES
3554 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003555 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003556#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003557#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003558 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3559 int options = ctxt->options;
3560
3561 ctxt->options -= XML_PARSE_NONET;
3562 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3563 ctxt->options = options;
3564 return(ret);
3565 }
3566
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003567 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003568 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003569 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003570 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003571 pref = xmlCatalogGetDefaults();
3572
Daniel Veillard561b7f82002-03-20 21:55:57 +00003573 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003574 /*
3575 * Do a local lookup
3576 */
Daniel Veillard42595322004-11-08 10:52:06 +00003577 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003578 ((pref == XML_CATA_ALLOW_ALL) ||
3579 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3580 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3581 (const xmlChar *) ID,
3582 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003583 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003584 /*
3585 * Try a global lookup
3586 */
3587 if ((resource == NULL) &&
3588 ((pref == XML_CATA_ALLOW_ALL) ||
3589 (pref == XML_CATA_ALLOW_GLOBAL))) {
3590 resource = xmlCatalogResolve((const xmlChar *) ID,
3591 (const xmlChar *) URL);
3592 }
3593 if ((resource == NULL) && (URL != NULL))
3594 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003595
Daniel Veillarda840b692003-10-19 13:35:37 +00003596 /*
3597 * TODO: do an URI lookup on the reference
3598 */
3599 if ((resource != NULL)
3600 && (!xmlSysIDExists((const char *) resource))) {
3601 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003602
Daniel Veillard42595322004-11-08 10:52:06 +00003603 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003604 ((pref == XML_CATA_ALLOW_ALL) ||
3605 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3606 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3607 }
3608 if ((tmp == NULL) &&
3609 ((pref == XML_CATA_ALLOW_ALL) ||
3610 (pref == XML_CATA_ALLOW_GLOBAL))) {
3611 tmp = xmlCatalogResolveURI(resource);
3612 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003613
Daniel Veillarda840b692003-10-19 13:35:37 +00003614 if (tmp != NULL) {
3615 xmlFree(resource);
3616 resource = tmp;
3617 }
3618 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003619 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003620#endif
3621
3622 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003623 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003624
3625 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003626 if (ID == NULL)
3627 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003628 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003629 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003630 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003631 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003632 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003633 xmlFree(resource);
3634 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003635}
3636
3637static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3638 xmlDefaultExternalEntityLoader;
3639
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003640/**
Owen Taylor3473f882001-02-23 17:55:21 +00003641 * xmlSetExternalEntityLoader:
3642 * @f: the new entity resolver function
3643 *
3644 * Changes the defaultexternal entity resolver function for the application
3645 */
3646void
3647xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3648 xmlCurrentExternalEntityLoader = f;
3649}
3650
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003651/**
Owen Taylor3473f882001-02-23 17:55:21 +00003652 * xmlGetExternalEntityLoader:
3653 *
3654 * Get the default external entity resolver function for the application
3655 *
3656 * Returns the xmlExternalEntityLoader function pointer
3657 */
3658xmlExternalEntityLoader
3659xmlGetExternalEntityLoader(void) {
3660 return(xmlCurrentExternalEntityLoader);
3661}
3662
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003663/**
Owen Taylor3473f882001-02-23 17:55:21 +00003664 * xmlLoadExternalEntity:
3665 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003666 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003667 * @ctxt: the context in which the entity is called or NULL
3668 *
3669 * Load an external entity, note that the use of this function for
3670 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003671 *
3672 * Returns the xmlParserInputPtr or NULL
3673 */
3674xmlParserInputPtr
3675xmlLoadExternalEntity(const char *URL, const char *ID,
3676 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003677 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3678 char *canonicFilename;
3679 xmlParserInputPtr ret;
3680
3681 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3682 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003683 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003684 return(NULL);
3685 }
3686
3687 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3688 xmlFree(canonicFilename);
3689 return(ret);
3690 }
Owen Taylor3473f882001-02-23 17:55:21 +00003691 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3692}
3693
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003694/************************************************************************
3695 * *
3696 * Disabling Network access *
3697 * *
3698 ************************************************************************/
3699
3700#ifdef LIBXML_CATALOG_ENABLED
3701static int
3702xmlNoNetExists(const char *URL)
3703{
3704#ifdef HAVE_STAT
3705 int ret;
3706 struct stat info;
3707 const char *path;
3708
3709 if (URL == NULL)
3710 return (0);
3711
Daniel Veillardf4862f02002-09-10 11:13:43 +00003712 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003713#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003714 path = &URL[17];
3715#else
3716 path = &URL[16];
3717#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003718 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003719#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003720 path = &URL[8];
3721#else
3722 path = &URL[7];
3723#endif
3724 } else
3725 path = URL;
3726 ret = stat(path, &info);
3727 if (ret == 0)
3728 return (1);
3729#endif
3730 return (0);
3731}
3732#endif
3733
3734/**
3735 * xmlNoNetExternalEntityLoader:
3736 * @URL: the URL for the entity to load
3737 * @ID: the System ID for the entity to load
3738 * @ctxt: the context in which the entity is called or NULL
3739 *
3740 * A specific entity loader disabling network accesses, though still
3741 * allowing local catalog accesses for resolution.
3742 *
3743 * Returns a new allocated xmlParserInputPtr, or NULL.
3744 */
3745xmlParserInputPtr
3746xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3747 xmlParserCtxtPtr ctxt) {
3748 xmlParserInputPtr input = NULL;
3749 xmlChar *resource = NULL;
3750
3751#ifdef LIBXML_CATALOG_ENABLED
3752 xmlCatalogAllow pref;
3753
3754 /*
3755 * If the resource doesn't exists as a file,
3756 * try to load it from the resource pointed in the catalogs
3757 */
3758 pref = xmlCatalogGetDefaults();
3759
3760 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3761 /*
3762 * Do a local lookup
3763 */
Daniel Veillard42595322004-11-08 10:52:06 +00003764 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003765 ((pref == XML_CATA_ALLOW_ALL) ||
3766 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3767 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3768 (const xmlChar *)ID,
3769 (const xmlChar *)URL);
3770 }
3771 /*
3772 * Try a global lookup
3773 */
3774 if ((resource == NULL) &&
3775 ((pref == XML_CATA_ALLOW_ALL) ||
3776 (pref == XML_CATA_ALLOW_GLOBAL))) {
3777 resource = xmlCatalogResolve((const xmlChar *)ID,
3778 (const xmlChar *)URL);
3779 }
3780 if ((resource == NULL) && (URL != NULL))
3781 resource = xmlStrdup((const xmlChar *) URL);
3782
3783 /*
3784 * TODO: do an URI lookup on the reference
3785 */
3786 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3787 xmlChar *tmp = NULL;
3788
Daniel Veillard42595322004-11-08 10:52:06 +00003789 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003790 ((pref == XML_CATA_ALLOW_ALL) ||
3791 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3792 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3793 }
3794 if ((tmp == NULL) &&
3795 ((pref == XML_CATA_ALLOW_ALL) ||
3796 (pref == XML_CATA_ALLOW_GLOBAL))) {
3797 tmp = xmlCatalogResolveURI(resource);
3798 }
3799
3800 if (tmp != NULL) {
3801 xmlFree(resource);
3802 resource = tmp;
3803 }
3804 }
3805 }
3806#endif
3807 if (resource == NULL)
3808 resource = (xmlChar *) URL;
3809
3810 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003811 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3812 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003813 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003814 if (resource != (xmlChar *) URL)
3815 xmlFree(resource);
3816 return(NULL);
3817 }
3818 }
3819 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3820 if (resource != (xmlChar *) URL)
3821 xmlFree(resource);
3822 return(input);
3823}
3824
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003825#define bottom_xmlIO
3826#include "elfgcchack.h"