blob: 12516652c92e241aae6f5de71f82c3025708e0a0 [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 Veillardf7416012006-04-27 08:15:20 +0000592 if (path == NULL)
593 return(0);
594
595#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
596 {
597 int retval = 0;
598
599 wchar_t *wPath = __xmlIOWin32UTF8ToWChar(path);
600 if (wPath)
601 {
602 struct _stat stat_buffer;
603
604 if (_wstat(wPath,&stat_buffer) == 0)
605 {
606 retval = 1;
607
608 if (((stat_buffer.st_mode & S_IFDIR) == S_IFDIR))
609 retval = 2;
610 }
611
612 free(wPath);
613 }
614
615 return retval;
616 }
617#else
Owen Taylor3473f882001-02-23 17:55:21 +0000618#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000619 struct stat stat_buffer;
620
621 if (stat(path, &stat_buffer) == -1)
622 return 0;
623
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000624#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000625 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000626 return 2;
Daniel Veillardf7416012006-04-27 08:15:20 +0000627#endif /* S_ISDIR */
628#endif /* HAVE_STAT */
629#endif /* WIN32 */
Daniel Veillard34099b42004-11-04 17:34:35 +0000630
Owen Taylor3473f882001-02-23 17:55:21 +0000631 return 1;
632}
633
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000634static int
Owen Taylor3473f882001-02-23 17:55:21 +0000635xmlNop(void) {
636 return(0);
637}
638
639/**
Owen Taylor3473f882001-02-23 17:55:21 +0000640 * xmlFdRead:
641 * @context: the I/O context
642 * @buffer: where to drop data
643 * @len: number of bytes to read
644 *
645 * Read @len bytes to @buffer from the I/O channel.
646 *
647 * Returns the number of bytes written
648 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000649static int
Owen Taylor3473f882001-02-23 17:55:21 +0000650xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000651 int ret;
652
653 ret = read((int) (long) context, &buffer[0], len);
654 if (ret < 0) xmlIOErr(0, "read()");
655 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000656}
657
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000658#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000659/**
660 * xmlFdWrite:
661 * @context: the I/O context
662 * @buffer: where to get data
663 * @len: number of bytes to write
664 *
665 * Write @len bytes from @buffer to the I/O channel.
666 *
667 * Returns the number of bytes written
668 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000669static int
Owen Taylor3473f882001-02-23 17:55:21 +0000670xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000671 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000672
Daniel Veillard9b693b42005-10-28 14:54:17 +0000673 if (len > 0) {
674 ret = write((int) (long) context, &buffer[0], len);
675 if (ret < 0) xmlIOErr(0, "write()");
676 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000677 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000678}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000679#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000680
681/**
682 * xmlFdClose:
683 * @context: the I/O context
684 *
685 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000686 *
687 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000688 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000689static int
Owen Taylor3473f882001-02-23 17:55:21 +0000690xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000691 int ret;
692 ret = close((int) (long) context);
693 if (ret < 0) xmlIOErr(0, "close()");
694 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000695}
696
697/**
698 * xmlFileMatch:
699 * @filename: the URI for matching
700 *
701 * input from FILE *
702 *
703 * Returns 1 if matches, 0 otherwise
704 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000705int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000706xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000707 return(1);
708}
709
710/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000711 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000712 * @filename: the URI for matching
713 *
714 * input from FILE *, supports compressed input
715 * if @filename is " " then the standard input is used
716 *
717 * Returns an I/O context or NULL in case of error
718 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000719static void *
720xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000721 const char *path = NULL;
722 FILE *fd;
723
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000724 if (filename == NULL)
725 return(NULL);
726
Owen Taylor3473f882001-02-23 17:55:21 +0000727 if (!strcmp(filename, "-")) {
728 fd = stdin;
729 return((void *) fd);
730 }
731
Daniel Veillardf4862f02002-09-10 11:13:43 +0000732 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000733#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000734 path = &filename[17];
735#else
Owen Taylor3473f882001-02-23 17:55:21 +0000736 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000737#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000738 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000739#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000740 path = &filename[8];
741#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000742 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000743#endif
744 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000745 path = filename;
746
747 if (path == NULL)
748 return(NULL);
749 if (!xmlCheckFilename(path))
750 return(NULL);
751
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000752#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000753 {
754 wchar_t *wPath = __xmlIOWin32UTF8ToWChar(path);
755 if (wPath)
756 {
757 fd = _wfopen(wPath, L"rb");
758 free(wPath);
759 }
760 else
761 {
762 fd = fopen(path, "rb");
763 }
764 }
Owen Taylor3473f882001-02-23 17:55:21 +0000765#else
766 fd = fopen(path, "r");
767#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000768 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000769 return((void *) fd);
770}
771
772/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000773 * xmlFileOpen:
774 * @filename: the URI for matching
775 *
776 * Wrapper around xmlFileOpen_real that try it with an unescaped
777 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000778 *
779 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000780 */
781void *
782xmlFileOpen (const char *filename) {
783 char *unescaped;
784 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000785
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000786 unescaped = xmlURIUnescapeString(filename, 0, NULL);
787 if (unescaped != NULL) {
788 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000789 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000790 } else {
791 retval = xmlFileOpen_real(filename);
792 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000793 return retval;
794}
795
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000796#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000797/**
Owen Taylor3473f882001-02-23 17:55:21 +0000798 * xmlFileOpenW:
799 * @filename: the URI for matching
800 *
801 * output to from FILE *,
802 * if @filename is "-" then the standard output is used
803 *
804 * Returns an I/O context or NULL in case of error
805 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000806static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000807xmlFileOpenW (const char *filename) {
808 const char *path = NULL;
809 FILE *fd;
810
811 if (!strcmp(filename, "-")) {
812 fd = stdout;
813 return((void *) fd);
814 }
815
Daniel Veillardf4862f02002-09-10 11:13:43 +0000816 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000817#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000818 path = &filename[17];
819#else
Owen Taylor3473f882001-02-23 17:55:21 +0000820 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000821#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000822 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000823#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000824 path = &filename[8];
825#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000826 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000827#endif
828 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000829 path = filename;
830
831 if (path == NULL)
832 return(NULL);
833
Daniel Veillardf7416012006-04-27 08:15:20 +0000834#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
835 {
836 wchar_t *wPath = __xmlIOWin32UTF8ToWChar(path);
837 if (wPath)
838 {
839 fd = _wfopen(wPath, L"wb");
840 free(wPath);
841 }
842 else
843 {
844 fd = fopen(path, "wb");
845 }
846 }
847#else
848 fd = fopen(path, "wb");
849#endif /* WIN32 */
850
851 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000852 return((void *) fd);
853}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000854#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000855
856/**
857 * xmlFileRead:
858 * @context: the I/O context
859 * @buffer: where to drop data
860 * @len: number of bytes to write
861 *
862 * Read @len bytes to @buffer from the I/O channel.
863 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000864 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000865 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000866int
Owen Taylor3473f882001-02-23 17:55:21 +0000867xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000868 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000869 if ((context == NULL) || (buffer == NULL))
870 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000871 ret = fread(&buffer[0], 1, len, (FILE *) context);
872 if (ret < 0) xmlIOErr(0, "fread()");
873 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000874}
875
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000876#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000877/**
878 * xmlFileWrite:
879 * @context: the I/O context
880 * @buffer: where to drop data
881 * @len: number of bytes to write
882 *
883 * Write @len bytes from @buffer to the I/O channel.
884 *
885 * Returns the number of bytes written
886 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000887static int
Owen Taylor3473f882001-02-23 17:55:21 +0000888xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000889 int items;
890
Daniel Veillardce682bc2004-11-05 17:22:25 +0000891 if ((context == NULL) || (buffer == NULL))
892 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000893 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000894 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000895 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000896 return(-1);
897 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000898 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000899}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000900#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000901
902/**
903 * xmlFileClose:
904 * @context: the I/O context
905 *
906 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000907 *
908 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000909 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000910int
Owen Taylor3473f882001-02-23 17:55:21 +0000911xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000912 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000913 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000914
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000915 if (context == NULL)
916 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000917 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000918 if ((fil == stdout) || (fil == stderr)) {
919 ret = fflush(fil);
920 if (ret < 0)
921 xmlIOErr(0, "fflush()");
922 return(0);
923 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000924 if (fil == stdin)
925 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000926 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
927 if (ret < 0)
928 xmlIOErr(0, "fclose()");
929 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000930}
931
932/**
933 * xmlFileFlush:
934 * @context: the I/O context
935 *
936 * Flush an I/O channel
937 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000938static int
Owen Taylor3473f882001-02-23 17:55:21 +0000939xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000940 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000941
942 if (context == NULL)
943 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000944 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
945 if (ret < 0)
946 xmlIOErr(0, "fflush()");
947 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000948}
949
Daniel Veillard9a00fd22005-11-09 08:56:26 +0000950#ifdef LIBXML_OUTPUT_ENABLED
951/**
952 * xmlBufferWrite:
953 * @context: the xmlBuffer
954 * @buffer: the data to write
955 * @len: number of bytes to write
956 *
957 * Write @len bytes from @buffer to the xml buffer
958 *
959 * Returns the number of bytes written
960 */
961static int
962xmlBufferWrite (void * context, const char * buffer, int len) {
963 int ret;
964
965 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
966 if (ret != 0)
967 return(-1);
968 return(len);
969}
Daniel Veillard9a00fd22005-11-09 08:56:26 +0000970#endif
971
Owen Taylor3473f882001-02-23 17:55:21 +0000972#ifdef HAVE_ZLIB_H
973/************************************************************************
974 * *
975 * I/O for compressed file accesses *
976 * *
977 ************************************************************************/
978/**
979 * xmlGzfileMatch:
980 * @filename: the URI for matching
981 *
982 * input from compressed file test
983 *
984 * Returns 1 if matches, 0 otherwise
985 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000986static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000987xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000988 return(1);
989}
990
991/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000992 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000993 * @filename: the URI for matching
994 *
995 * input from compressed file open
996 * if @filename is " " then the standard input is used
997 *
998 * Returns an I/O context or NULL in case of error
999 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001000static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001001xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001002 const char *path = NULL;
1003 gzFile fd;
1004
1005 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001006 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001007 return((void *) fd);
1008 }
1009
Daniel Veillardf4862f02002-09-10 11:13:43 +00001010 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001011#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001012 path = &filename[17];
1013#else
Owen Taylor3473f882001-02-23 17:55:21 +00001014 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001015#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001016 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001017#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001018 path = &filename[8];
1019#else
Owen Taylor3473f882001-02-23 17:55:21 +00001020 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001021#endif
1022 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001023 path = filename;
1024
1025 if (path == NULL)
1026 return(NULL);
1027 if (!xmlCheckFilename(path))
1028 return(NULL);
1029
1030 fd = gzopen(path, "rb");
1031 return((void *) fd);
1032}
1033
1034/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001035 * xmlGzfileOpen:
1036 * @filename: the URI for matching
1037 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001038 * Wrapper around xmlGzfileOpen if the open fais, it will
1039 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001040 */
1041static void *
1042xmlGzfileOpen (const char *filename) {
1043 char *unescaped;
1044 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001045
1046 retval = xmlGzfileOpen_real(filename);
1047 if (retval == NULL) {
1048 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1049 if (unescaped != NULL) {
1050 retval = xmlGzfileOpen_real(unescaped);
1051 }
1052 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001053 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001054 return retval;
1055}
1056
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001057#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001058/**
Owen Taylor3473f882001-02-23 17:55:21 +00001059 * xmlGzfileOpenW:
1060 * @filename: the URI for matching
1061 * @compression: the compression factor (0 - 9 included)
1062 *
1063 * input from compressed file open
1064 * if @filename is " " then the standard input is used
1065 *
1066 * Returns an I/O context or NULL in case of error
1067 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001068static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001069xmlGzfileOpenW (const char *filename, int compression) {
1070 const char *path = NULL;
1071 char mode[15];
1072 gzFile fd;
1073
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001074 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001075 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001076 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001077 return((void *) fd);
1078 }
1079
Daniel Veillardf4862f02002-09-10 11:13:43 +00001080 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001081#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001082 path = &filename[17];
1083#else
Owen Taylor3473f882001-02-23 17:55:21 +00001084 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001085#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001086 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001087#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001088 path = &filename[8];
1089#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001090 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001091#endif
1092 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001093 path = filename;
1094
1095 if (path == NULL)
1096 return(NULL);
1097
1098 fd = gzopen(path, mode);
1099 return((void *) fd);
1100}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001101#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001102
1103/**
1104 * xmlGzfileRead:
1105 * @context: the I/O context
1106 * @buffer: where to drop data
1107 * @len: number of bytes to write
1108 *
1109 * Read @len bytes to @buffer from the compressed I/O channel.
1110 *
1111 * Returns the number of bytes written
1112 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001113static int
Owen Taylor3473f882001-02-23 17:55:21 +00001114xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001115 int ret;
1116
1117 ret = gzread((gzFile) context, &buffer[0], len);
1118 if (ret < 0) xmlIOErr(0, "gzread()");
1119 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001120}
1121
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001122#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001123/**
1124 * xmlGzfileWrite:
1125 * @context: the I/O context
1126 * @buffer: where to drop data
1127 * @len: number of bytes to write
1128 *
1129 * Write @len bytes from @buffer to the compressed I/O channel.
1130 *
1131 * Returns the number of bytes written
1132 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001133static int
Owen Taylor3473f882001-02-23 17:55:21 +00001134xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001135 int ret;
1136
1137 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1138 if (ret < 0) xmlIOErr(0, "gzwrite()");
1139 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001140}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001141#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001142
1143/**
1144 * xmlGzfileClose:
1145 * @context: the I/O context
1146 *
1147 * Close a compressed I/O channel
1148 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001149static int
Owen Taylor3473f882001-02-23 17:55:21 +00001150xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001151 int ret;
1152
1153 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1154 if (ret < 0) xmlIOErr(0, "gzclose()");
1155 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001156}
1157#endif /* HAVE_ZLIB_H */
1158
1159#ifdef LIBXML_HTTP_ENABLED
1160/************************************************************************
1161 * *
1162 * I/O for HTTP file accesses *
1163 * *
1164 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001165
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001166#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001167typedef struct xmlIOHTTPWriteCtxt_
1168{
1169 int compression;
1170
1171 char * uri;
1172
1173 void * doc_buff;
1174
1175} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1176
1177#ifdef HAVE_ZLIB_H
1178
1179#define DFLT_WBITS ( -15 )
1180#define DFLT_MEM_LVL ( 8 )
1181#define GZ_MAGIC1 ( 0x1f )
1182#define GZ_MAGIC2 ( 0x8b )
1183#define LXML_ZLIB_OS_CODE ( 0x03 )
1184#define INIT_HTTP_BUFF_SIZE ( 32768 )
1185#define DFLT_ZLIB_RATIO ( 5 )
1186
1187/*
1188** Data structure and functions to work with sending compressed data
1189** via HTTP.
1190*/
1191
1192typedef struct xmlZMemBuff_
1193{
1194 unsigned long size;
1195 unsigned long crc;
1196
1197 unsigned char * zbuff;
1198 z_stream zctrl;
1199
1200} xmlZMemBuff, *xmlZMemBuffPtr;
1201
1202/**
1203 * append_reverse_ulong
1204 * @buff: Compressed memory buffer
1205 * @data: Unsigned long to append
1206 *
1207 * Append a unsigned long in reverse byte order to the end of the
1208 * memory buffer.
1209 */
1210static void
1211append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1212
1213 int idx;
1214
1215 if ( buff == NULL )
1216 return;
1217
1218 /*
1219 ** This is plagiarized from putLong in gzio.c (zlib source) where
1220 ** the number "4" is hardcoded. If zlib is ever patched to
1221 ** support 64 bit file sizes, this code would need to be patched
1222 ** as well.
1223 */
1224
1225 for ( idx = 0; idx < 4; idx++ ) {
1226 *buff->zctrl.next_out = ( data & 0xff );
1227 data >>= 8;
1228 buff->zctrl.next_out++;
1229 }
1230
1231 return;
1232}
1233
1234/**
1235 *
1236 * xmlFreeZMemBuff
1237 * @buff: The memory buffer context to clear
1238 *
1239 * Release all the resources associated with the compressed memory buffer.
1240 */
1241static void
1242xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001243
1244#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001245 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001246#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001247
1248 if ( buff == NULL )
1249 return;
1250
1251 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001252#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001253 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001254 if ( z_err != Z_OK )
1255 xmlGenericError( xmlGenericErrorContext,
1256 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1257 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001258#else
1259 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001260#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001261
1262 xmlFree( buff );
1263 return;
1264}
1265
1266/**
1267 * xmlCreateZMemBuff
1268 *@compression: Compression value to use
1269 *
1270 * Create a memory buffer to hold the compressed XML document. The
1271 * compressed document in memory will end up being identical to what
1272 * would be created if gzopen/gzwrite/gzclose were being used to
1273 * write the document to disk. The code for the header/trailer data to
1274 * the compression is plagiarized from the zlib source files.
1275 */
1276static void *
1277xmlCreateZMemBuff( int compression ) {
1278
1279 int z_err;
1280 int hdr_lgth;
1281 xmlZMemBuffPtr buff = NULL;
1282
1283 if ( ( compression < 1 ) || ( compression > 9 ) )
1284 return ( NULL );
1285
1286 /* Create the control and data areas */
1287
1288 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1289 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001290 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001291 return ( NULL );
1292 }
1293
1294 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1295 buff->size = INIT_HTTP_BUFF_SIZE;
1296 buff->zbuff = xmlMalloc( buff->size );
1297 if ( buff->zbuff == NULL ) {
1298 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001299 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001300 return ( NULL );
1301 }
1302
1303 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1304 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1305 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001306 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001307 xmlFreeZMemBuff( buff );
1308 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001309 xmlStrPrintf(msg, 500,
1310 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1311 "Error initializing compression context. ZLIB error:",
1312 z_err );
1313 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001314 return ( NULL );
1315 }
1316
1317 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001318 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001319 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1320 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001321 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1322 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1323 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1324 buff->zctrl.avail_out = buff->size - hdr_lgth;
1325
1326 return ( buff );
1327}
1328
1329/**
1330 * xmlZMemBuffExtend
1331 * @buff: Buffer used to compress and consolidate data.
1332 * @ext_amt: Number of bytes to extend the buffer.
1333 *
1334 * Extend the internal buffer used to store the compressed data by the
1335 * specified amount.
1336 *
1337 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1338 * the original buffer still exists at the original size.
1339 */
1340static int
1341xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1342
1343 int rc = -1;
1344 size_t new_size;
1345 size_t cur_used;
1346
1347 unsigned char * tmp_ptr = NULL;
1348
1349 if ( buff == NULL )
1350 return ( -1 );
1351
1352 else if ( ext_amt == 0 )
1353 return ( 0 );
1354
1355 cur_used = buff->zctrl.next_out - buff->zbuff;
1356 new_size = buff->size + ext_amt;
1357
1358#ifdef DEBUG_HTTP
1359 if ( cur_used > new_size )
1360 xmlGenericError( xmlGenericErrorContext,
1361 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1362 "Buffer overwrite detected during compressed memory",
1363 "buffer extension. Overflowed by",
1364 (cur_used - new_size ) );
1365#endif
1366
1367 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1368 if ( tmp_ptr != NULL ) {
1369 rc = 0;
1370 buff->size = new_size;
1371 buff->zbuff = tmp_ptr;
1372 buff->zctrl.next_out = tmp_ptr + cur_used;
1373 buff->zctrl.avail_out = new_size - cur_used;
1374 }
1375 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001376 xmlChar msg[500];
1377 xmlStrPrintf(msg, 500,
1378 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1379 "Allocation failure extending output buffer to",
1380 new_size );
1381 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001382 }
1383
1384 return ( rc );
1385}
1386
1387/**
1388 * xmlZMemBuffAppend
1389 * @buff: Buffer used to compress and consolidate data
1390 * @src: Uncompressed source content to append to buffer
1391 * @len: Length of source data to append to buffer
1392 *
1393 * Compress and append data to the internal buffer. The data buffer
1394 * will be expanded if needed to store the additional data.
1395 *
1396 * Returns the number of bytes appended to the buffer or -1 on error.
1397 */
1398static int
1399xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1400
1401 int z_err;
1402 size_t min_accept;
1403
1404 if ( ( buff == NULL ) || ( src == NULL ) )
1405 return ( -1 );
1406
1407 buff->zctrl.avail_in = len;
1408 buff->zctrl.next_in = (unsigned char *)src;
1409 while ( buff->zctrl.avail_in > 0 ) {
1410 /*
1411 ** Extend the buffer prior to deflate call if a reasonable amount
1412 ** of output buffer space is not available.
1413 */
1414 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1415 if ( buff->zctrl.avail_out <= min_accept ) {
1416 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1417 return ( -1 );
1418 }
1419
1420 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1421 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001422 xmlChar msg[500];
1423 xmlStrPrintf(msg, 500,
1424 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001425 "Compression error while appending",
1426 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001427 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001428 return ( -1 );
1429 }
1430 }
1431
1432 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1433
1434 return ( len );
1435}
1436
1437/**
1438 * xmlZMemBuffGetContent
1439 * @buff: Compressed memory content buffer
1440 * @data_ref: Pointer reference to point to compressed content
1441 *
1442 * Flushes the compression buffers, appends gzip file trailers and
1443 * returns the compressed content and length of the compressed data.
1444 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1445 *
1446 * Returns the length of the compressed data or -1 on error.
1447 */
1448static int
1449xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1450
1451 int zlgth = -1;
1452 int z_err;
1453
1454 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1455 return ( -1 );
1456
1457 /* Need to loop until compression output buffers are flushed */
1458
1459 do
1460 {
1461 z_err = deflate( &buff->zctrl, Z_FINISH );
1462 if ( z_err == Z_OK ) {
1463 /* In this case Z_OK means more buffer space needed */
1464
1465 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1466 return ( -1 );
1467 }
1468 }
1469 while ( z_err == Z_OK );
1470
1471 /* If the compression state is not Z_STREAM_END, some error occurred */
1472
1473 if ( z_err == Z_STREAM_END ) {
1474
1475 /* Need to append the gzip data trailer */
1476
1477 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1478 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1479 return ( -1 );
1480 }
1481
1482 /*
1483 ** For whatever reason, the CRC and length data are pushed out
1484 ** in reverse byte order. So a memcpy can't be used here.
1485 */
1486
1487 append_reverse_ulong( buff, buff->crc );
1488 append_reverse_ulong( buff, buff->zctrl.total_in );
1489
1490 zlgth = buff->zctrl.next_out - buff->zbuff;
1491 *data_ref = (char *)buff->zbuff;
1492 }
1493
Daniel Veillard05d987b2003-10-08 11:54:57 +00001494 else {
1495 xmlChar msg[500];
1496 xmlStrPrintf(msg, 500,
1497 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1498 "Error flushing zlib buffers. Error code", z_err );
1499 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1500 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001501
1502 return ( zlgth );
1503}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001504#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001505#endif /* HAVE_ZLIB_H */
1506
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001507#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001508/**
1509 * xmlFreeHTTPWriteCtxt
1510 * @ctxt: Context to cleanup
1511 *
1512 * Free allocated memory and reclaim system resources.
1513 *
1514 * No return value.
1515 */
1516static void
1517xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1518{
1519 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001520 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001521
1522 if ( ctxt->doc_buff != NULL ) {
1523
1524#ifdef HAVE_ZLIB_H
1525 if ( ctxt->compression > 0 ) {
1526 xmlFreeZMemBuff( ctxt->doc_buff );
1527 }
1528 else
1529#endif
1530 {
1531 xmlOutputBufferClose( ctxt->doc_buff );
1532 }
1533 }
1534
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001535 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001536 return;
1537}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001538#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001539
1540
Owen Taylor3473f882001-02-23 17:55:21 +00001541/**
1542 * xmlIOHTTPMatch:
1543 * @filename: the URI for matching
1544 *
1545 * check if the URI matches an HTTP one
1546 *
1547 * Returns 1 if matches, 0 otherwise
1548 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001549int
Owen Taylor3473f882001-02-23 17:55:21 +00001550xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001551 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001552 return(1);
1553 return(0);
1554}
1555
1556/**
1557 * xmlIOHTTPOpen:
1558 * @filename: the URI for matching
1559 *
1560 * open an HTTP I/O channel
1561 *
1562 * Returns an I/O context or NULL in case of error
1563 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001564void *
Owen Taylor3473f882001-02-23 17:55:21 +00001565xmlIOHTTPOpen (const char *filename) {
1566 return(xmlNanoHTTPOpen(filename, NULL));
1567}
1568
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001569#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001570/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001571 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001572 * @post_uri: The destination URI for the document
1573 * @compression: The compression desired for the document.
1574 *
1575 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1576 * request. Non-static as is called from the output buffer creation routine.
1577 *
1578 * Returns an I/O context or NULL in case of error.
1579 */
1580
1581void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001582xmlIOHTTPOpenW(const char *post_uri, int compression)
1583{
Daniel Veillardf012a642001-07-23 19:10:52 +00001584
Daniel Veillard572577e2002-01-18 16:23:55 +00001585 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001586
Daniel Veillard572577e2002-01-18 16:23:55 +00001587 if (post_uri == NULL)
1588 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001589
Daniel Veillard572577e2002-01-18 16:23:55 +00001590 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1591 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001592 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001593 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001594 }
1595
Daniel Veillard572577e2002-01-18 16:23:55 +00001596 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001597
Daniel Veillard572577e2002-01-18 16:23:55 +00001598 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1599 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001600 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001601 xmlFreeHTTPWriteCtxt(ctxt);
1602 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001603 }
1604
1605 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001606 * ** Since the document length is required for an HTTP post,
1607 * ** need to put the document into a buffer. A memory buffer
1608 * ** is being used to avoid pushing the data to disk and back.
1609 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001610
1611#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001612 if ((compression > 0) && (compression <= 9)) {
1613
1614 ctxt->compression = compression;
1615 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1616 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001617#endif
1618 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001619 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001620
Daniel Veillard572577e2002-01-18 16:23:55 +00001621 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001622 }
1623
Daniel Veillard572577e2002-01-18 16:23:55 +00001624 if (ctxt->doc_buff == NULL) {
1625 xmlFreeHTTPWriteCtxt(ctxt);
1626 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001627 }
1628
Daniel Veillard572577e2002-01-18 16:23:55 +00001629 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001630}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001631#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001632
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001633#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001634/**
1635 * xmlIOHTTPDfltOpenW
1636 * @post_uri: The destination URI for this document.
1637 *
1638 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1639 * HTTP post command. This function should generally not be used as
1640 * the open callback is short circuited in xmlOutputBufferCreateFile.
1641 *
1642 * Returns a pointer to the new IO context.
1643 */
1644static void *
1645xmlIOHTTPDfltOpenW( const char * post_uri ) {
1646 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1647}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001648#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001649
1650/**
Owen Taylor3473f882001-02-23 17:55:21 +00001651 * xmlIOHTTPRead:
1652 * @context: the I/O context
1653 * @buffer: where to drop data
1654 * @len: number of bytes to write
1655 *
1656 * Read @len bytes to @buffer from the I/O channel.
1657 *
1658 * Returns the number of bytes written
1659 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001660int
Owen Taylor3473f882001-02-23 17:55:21 +00001661xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001662 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001663 return(xmlNanoHTTPRead(context, &buffer[0], len));
1664}
1665
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001666#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001667/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001668 * xmlIOHTTPWrite
1669 * @context: previously opened writing context
1670 * @buffer: data to output to temporary buffer
1671 * @len: bytes to output
1672 *
1673 * Collect data from memory buffer into a temporary file for later
1674 * processing.
1675 *
1676 * Returns number of bytes written.
1677 */
1678
1679static int
1680xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1681
1682 xmlIOHTTPWriteCtxtPtr ctxt = context;
1683
1684 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1685 return ( -1 );
1686
1687 if ( len > 0 ) {
1688
1689 /* Use gzwrite or fwrite as previously setup in the open call */
1690
1691#ifdef HAVE_ZLIB_H
1692 if ( ctxt->compression > 0 )
1693 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1694
1695 else
1696#endif
1697 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1698
1699 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001700 xmlChar msg[500];
1701 xmlStrPrintf(msg, 500,
1702 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001703 "Error appending to internal buffer.",
1704 "Error sending document to URI",
1705 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001706 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001707 }
1708 }
1709
1710 return ( len );
1711}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001712#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001713
1714
1715/**
Owen Taylor3473f882001-02-23 17:55:21 +00001716 * xmlIOHTTPClose:
1717 * @context: the I/O context
1718 *
1719 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001720 *
1721 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001722 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001723int
Owen Taylor3473f882001-02-23 17:55:21 +00001724xmlIOHTTPClose (void * context) {
1725 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001726 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001727}
Daniel Veillardf012a642001-07-23 19:10:52 +00001728
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001729#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001730/**
1731 * xmlIOHTTCloseWrite
1732 * @context: The I/O context
1733 * @http_mthd: The HTTP method to be used when sending the data
1734 *
1735 * Close the transmit HTTP I/O channel and actually send the data.
1736 */
1737static int
1738xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1739
1740 int close_rc = -1;
1741 int http_rtn = 0;
1742 int content_lgth = 0;
1743 xmlIOHTTPWriteCtxtPtr ctxt = context;
1744
1745 char * http_content = NULL;
1746 char * content_encoding = NULL;
1747 char * content_type = (char *) "text/xml";
1748 void * http_ctxt = NULL;
1749
1750 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1751 return ( -1 );
1752
1753 /* Retrieve the content from the appropriate buffer */
1754
1755#ifdef HAVE_ZLIB_H
1756
1757 if ( ctxt->compression > 0 ) {
1758 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1759 content_encoding = (char *) "Content-Encoding: gzip";
1760 }
1761 else
1762#endif
1763 {
1764 /* Pull the data out of the memory output buffer */
1765
1766 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1767 http_content = (char *)dctxt->buffer->content;
1768 content_lgth = dctxt->buffer->use;
1769 }
1770
1771 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001772 xmlChar msg[500];
1773 xmlStrPrintf(msg, 500,
1774 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1775 "Error retrieving content.\nUnable to",
1776 http_mthd, "data to URI", ctxt->uri );
1777 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001778 }
1779
1780 else {
1781
1782 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1783 &content_type, content_encoding,
1784 content_lgth );
1785
1786 if ( http_ctxt != NULL ) {
1787#ifdef DEBUG_HTTP
1788 /* If testing/debugging - dump reply with request content */
1789
1790 FILE * tst_file = NULL;
1791 char buffer[ 4096 ];
1792 char * dump_name = NULL;
1793 int avail;
1794
1795 xmlGenericError( xmlGenericErrorContext,
1796 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1797 http_mthd, ctxt->uri,
1798 xmlNanoHTTPReturnCode( http_ctxt ) );
1799
1800 /*
1801 ** Since either content or reply may be gzipped,
1802 ** dump them to separate files instead of the
1803 ** standard error context.
1804 */
1805
1806 dump_name = tempnam( NULL, "lxml" );
1807 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001808 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001809
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001810 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001811 if ( tst_file != NULL ) {
1812 xmlGenericError( xmlGenericErrorContext,
1813 "Transmitted content saved in file: %s\n", buffer );
1814
1815 fwrite( http_content, sizeof( char ),
1816 content_lgth, tst_file );
1817 fclose( tst_file );
1818 }
1819
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001820 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001821 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001822 if ( tst_file != NULL ) {
1823 xmlGenericError( xmlGenericErrorContext,
1824 "Reply content saved in file: %s\n", buffer );
1825
1826
1827 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1828 buffer, sizeof( buffer ) )) > 0 ) {
1829
1830 fwrite( buffer, sizeof( char ), avail, tst_file );
1831 }
1832
1833 fclose( tst_file );
1834 }
1835
1836 free( dump_name );
1837 }
1838#endif /* DEBUG_HTTP */
1839
1840 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1841 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1842 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001843 else {
1844 xmlChar msg[500];
1845 xmlStrPrintf(msg, 500,
1846 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001847 http_mthd, content_lgth,
1848 "bytes to URI", ctxt->uri,
1849 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001850 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1851 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001852
1853 xmlNanoHTTPClose( http_ctxt );
1854 xmlFree( content_type );
1855 }
1856 }
1857
1858 /* Final cleanups */
1859
1860 xmlFreeHTTPWriteCtxt( ctxt );
1861
1862 return ( close_rc );
1863}
1864
1865/**
1866 * xmlIOHTTPClosePut
1867 *
1868 * @context: The I/O context
1869 *
1870 * Close the transmit HTTP I/O channel and actually send data using a PUT
1871 * HTTP method.
1872 */
1873static int
1874xmlIOHTTPClosePut( void * ctxt ) {
1875 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1876}
1877
1878
1879/**
1880 * xmlIOHTTPClosePost
1881 *
1882 * @context: The I/O context
1883 *
1884 * Close the transmit HTTP I/O channel and actually send data using a POST
1885 * HTTP method.
1886 */
1887static int
1888xmlIOHTTPClosePost( void * ctxt ) {
1889 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1890}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001891#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001892
Owen Taylor3473f882001-02-23 17:55:21 +00001893#endif /* LIBXML_HTTP_ENABLED */
1894
1895#ifdef LIBXML_FTP_ENABLED
1896/************************************************************************
1897 * *
1898 * I/O for FTP file accesses *
1899 * *
1900 ************************************************************************/
1901/**
1902 * xmlIOFTPMatch:
1903 * @filename: the URI for matching
1904 *
1905 * check if the URI matches an FTP one
1906 *
1907 * Returns 1 if matches, 0 otherwise
1908 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001909int
Owen Taylor3473f882001-02-23 17:55:21 +00001910xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001911 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001912 return(1);
1913 return(0);
1914}
1915
1916/**
1917 * xmlIOFTPOpen:
1918 * @filename: the URI for matching
1919 *
1920 * open an FTP I/O channel
1921 *
1922 * Returns an I/O context or NULL in case of error
1923 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001924void *
Owen Taylor3473f882001-02-23 17:55:21 +00001925xmlIOFTPOpen (const char *filename) {
1926 return(xmlNanoFTPOpen(filename));
1927}
1928
1929/**
1930 * xmlIOFTPRead:
1931 * @context: the I/O context
1932 * @buffer: where to drop data
1933 * @len: number of bytes to write
1934 *
1935 * Read @len bytes to @buffer from the I/O channel.
1936 *
1937 * Returns the number of bytes written
1938 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001939int
Owen Taylor3473f882001-02-23 17:55:21 +00001940xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001941 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001942 return(xmlNanoFTPRead(context, &buffer[0], len));
1943}
1944
1945/**
1946 * xmlIOFTPClose:
1947 * @context: the I/O context
1948 *
1949 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001950 *
1951 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001952 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001953int
Owen Taylor3473f882001-02-23 17:55:21 +00001954xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001955 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001956}
1957#endif /* LIBXML_FTP_ENABLED */
1958
1959
1960/**
1961 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001962 * @matchFunc: the xmlInputMatchCallback
1963 * @openFunc: the xmlInputOpenCallback
1964 * @readFunc: the xmlInputReadCallback
1965 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001966 *
1967 * Register a new set of I/O callback for handling parser input.
1968 *
1969 * Returns the registered handler number or -1 in case of error
1970 */
1971int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001972xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1973 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1974 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001975 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1976 return(-1);
1977 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001978 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1979 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1980 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1981 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001982 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001983 return(xmlInputCallbackNr++);
1984}
1985
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001986#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001987/**
1988 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001989 * @matchFunc: the xmlOutputMatchCallback
1990 * @openFunc: the xmlOutputOpenCallback
1991 * @writeFunc: the xmlOutputWriteCallback
1992 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001993 *
1994 * Register a new set of I/O callback for handling output.
1995 *
1996 * Returns the registered handler number or -1 in case of error
1997 */
1998int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001999xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2000 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2001 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002002 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
2003 return(-1);
2004 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002005 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2006 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2007 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2008 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002009 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002010 return(xmlOutputCallbackNr++);
2011}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002012#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002013
2014/**
2015 * xmlRegisterDefaultInputCallbacks:
2016 *
2017 * Registers the default compiled-in I/O handlers.
2018 */
2019void
Owen Taylor3473f882001-02-23 17:55:21 +00002020xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002021(void) {
2022 if (xmlInputCallbackInitialized)
2023 return;
2024
2025 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2026 xmlFileRead, xmlFileClose);
2027#ifdef HAVE_ZLIB_H
2028 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2029 xmlGzfileRead, xmlGzfileClose);
2030#endif /* HAVE_ZLIB_H */
2031
2032#ifdef LIBXML_HTTP_ENABLED
2033 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2034 xmlIOHTTPRead, xmlIOHTTPClose);
2035#endif /* LIBXML_HTTP_ENABLED */
2036
2037#ifdef LIBXML_FTP_ENABLED
2038 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2039 xmlIOFTPRead, xmlIOFTPClose);
2040#endif /* LIBXML_FTP_ENABLED */
2041 xmlInputCallbackInitialized = 1;
2042}
2043
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002044#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002045/**
2046 * xmlRegisterDefaultOutputCallbacks:
2047 *
2048 * Registers the default compiled-in I/O handlers.
2049 */
2050void
Owen Taylor3473f882001-02-23 17:55:21 +00002051xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002052(void) {
2053 if (xmlOutputCallbackInitialized)
2054 return;
2055
2056 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2057 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002058
2059#ifdef LIBXML_HTTP_ENABLED
2060 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2061 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2062#endif
2063
Owen Taylor3473f882001-02-23 17:55:21 +00002064/*********************************
2065 No way a-priori to distinguish between gzipped files from
2066 uncompressed ones except opening if existing then closing
2067 and saving with same compression ratio ... a pain.
2068
2069#ifdef HAVE_ZLIB_H
2070 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2071 xmlGzfileWrite, xmlGzfileClose);
2072#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002073
2074 Nor FTP PUT ....
2075#ifdef LIBXML_FTP_ENABLED
2076 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2077 xmlIOFTPWrite, xmlIOFTPClose);
2078#endif
2079 **********************************/
2080 xmlOutputCallbackInitialized = 1;
2081}
2082
Daniel Veillardf012a642001-07-23 19:10:52 +00002083#ifdef LIBXML_HTTP_ENABLED
2084/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002085 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002086 *
2087 * By default, libxml submits HTTP output requests using the "PUT" method.
2088 * Calling this method changes the HTTP output method to use the "POST"
2089 * method instead.
2090 *
2091 */
2092void
2093xmlRegisterHTTPPostCallbacks( void ) {
2094
2095 /* Register defaults if not done previously */
2096
2097 if ( xmlOutputCallbackInitialized == 0 )
2098 xmlRegisterDefaultOutputCallbacks( );
2099
2100 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2101 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2102 return;
2103}
2104#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002105#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002106
Owen Taylor3473f882001-02-23 17:55:21 +00002107/**
2108 * xmlAllocParserInputBuffer:
2109 * @enc: the charset encoding if known
2110 *
2111 * Create a buffered parser input for progressive parsing
2112 *
2113 * Returns the new parser input or NULL
2114 */
2115xmlParserInputBufferPtr
2116xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2117 xmlParserInputBufferPtr ret;
2118
2119 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2120 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002121 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002122 return(NULL);
2123 }
2124 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002125 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002126 if (ret->buffer == NULL) {
2127 xmlFree(ret);
2128 return(NULL);
2129 }
2130 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2131 ret->encoder = xmlGetCharEncodingHandler(enc);
2132 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002133 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002134 else
2135 ret->raw = NULL;
2136 ret->readcallback = NULL;
2137 ret->closecallback = NULL;
2138 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002139 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002140 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002141
2142 return(ret);
2143}
2144
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002145#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002146/**
2147 * xmlAllocOutputBuffer:
2148 * @encoder: the encoding converter or NULL
2149 *
2150 * Create a buffered parser output
2151 *
2152 * Returns the new parser output or NULL
2153 */
2154xmlOutputBufferPtr
2155xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2156 xmlOutputBufferPtr ret;
2157
2158 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2159 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002160 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002161 return(NULL);
2162 }
2163 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2164 ret->buffer = xmlBufferCreate();
2165 if (ret->buffer == NULL) {
2166 xmlFree(ret);
2167 return(NULL);
2168 }
2169 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2170 ret->encoder = encoder;
2171 if (encoder != NULL) {
2172 ret->conv = xmlBufferCreateSize(4000);
2173 /*
2174 * This call is designed to initiate the encoder state
2175 */
2176 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2177 } else
2178 ret->conv = NULL;
2179 ret->writecallback = NULL;
2180 ret->closecallback = NULL;
2181 ret->context = NULL;
2182 ret->written = 0;
2183
2184 return(ret);
2185}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002186#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002187
2188/**
2189 * xmlFreeParserInputBuffer:
2190 * @in: a buffered parser input
2191 *
2192 * Free up the memory used by a buffered parser input
2193 */
2194void
2195xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002196 if (in == NULL) return;
2197
Owen Taylor3473f882001-02-23 17:55:21 +00002198 if (in->raw) {
2199 xmlBufferFree(in->raw);
2200 in->raw = NULL;
2201 }
2202 if (in->encoder != NULL) {
2203 xmlCharEncCloseFunc(in->encoder);
2204 }
2205 if (in->closecallback != NULL) {
2206 in->closecallback(in->context);
2207 }
2208 if (in->buffer != NULL) {
2209 xmlBufferFree(in->buffer);
2210 in->buffer = NULL;
2211 }
2212
Owen Taylor3473f882001-02-23 17:55:21 +00002213 xmlFree(in);
2214}
2215
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002216#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002217/**
2218 * xmlOutputBufferClose:
2219 * @out: a buffered output
2220 *
2221 * flushes and close the output I/O channel
2222 * and free up all the associated resources
2223 *
2224 * Returns the number of byte written or -1 in case of error.
2225 */
2226int
Daniel Veillard828ce832003-10-08 19:19:10 +00002227xmlOutputBufferClose(xmlOutputBufferPtr out)
2228{
Owen Taylor3473f882001-02-23 17:55:21 +00002229 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002230 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002231
2232 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002233 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002234 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002235 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002236 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002237 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002238 }
2239 written = out->written;
2240 if (out->conv) {
2241 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002242 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002243 }
2244 if (out->encoder != NULL) {
2245 xmlCharEncCloseFunc(out->encoder);
2246 }
2247 if (out->buffer != NULL) {
2248 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002249 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002250 }
2251
Daniel Veillard828ce832003-10-08 19:19:10 +00002252 if (out->error)
2253 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002254 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002255 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002256}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002257#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002258
Daniel Veillard1b243b42004-06-08 10:16:42 +00002259xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002260__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002261 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002262 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002263 void *context = NULL;
2264
2265 if (xmlInputCallbackInitialized == 0)
2266 xmlRegisterDefaultInputCallbacks();
2267
2268 if (URI == NULL) return(NULL);
2269
2270 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002271 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002272 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002273 */
2274 if (context == NULL) {
2275 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2276 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2277 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002278 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002279 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002280 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002281 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002282 }
Owen Taylor3473f882001-02-23 17:55:21 +00002283 }
2284 }
2285 if (context == NULL) {
2286 return(NULL);
2287 }
2288
2289 /*
2290 * Allocate the Input buffer front-end.
2291 */
2292 ret = xmlAllocParserInputBuffer(enc);
2293 if (ret != NULL) {
2294 ret->context = context;
2295 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2296 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002297#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002298 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2299 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002300 if (((z_stream *)context)->avail_in > 4) {
2301 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002302 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002303 if (gzread(context, buff4, 4) == 4) {
2304 if (strncmp(buff4, cptr, 4) == 0)
2305 ret->compressed = 0;
2306 else
2307 ret->compressed = 1;
2308 gzrewind(context);
2309 }
2310 }
2311 }
2312#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002313 }
William M. Brack42331a92004-07-29 07:07:16 +00002314 else
2315 xmlInputCallbackTable[i].closecallback (context);
2316
Owen Taylor3473f882001-02-23 17:55:21 +00002317 return(ret);
2318}
2319
2320/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002321 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002322 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002323 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002324 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002325 * Create a buffered parser input for the progressive parsing of a file
2326 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002327 * Automatic support for ZLIB/Compress compressed document is provided
2328 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002329 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002330 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002331 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002332 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002333xmlParserInputBufferPtr
2334xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2335 if ((xmlParserInputBufferCreateFilenameValue)) {
2336 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2337 }
2338 return __xmlParserInputBufferCreateFilename(URI, enc);
2339}
2340
2341#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002342xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002343__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002344 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002345 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002346 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002347 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002348 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002349 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002350 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002351#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002352 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002353#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002354
Owen Taylor3473f882001-02-23 17:55:21 +00002355 if (xmlOutputCallbackInitialized == 0)
2356 xmlRegisterDefaultOutputCallbacks();
2357
2358 if (URI == NULL) return(NULL);
2359
Daniel Veillard966a31e2004-05-09 02:58:44 +00002360 puri = xmlParseURI(URI);
2361 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002362#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002363 if ((puri->scheme != NULL) &&
2364 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002365 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002366#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002367 /*
2368 * try to limit the damages of the URI unescaping code.
2369 */
2370 if (puri->scheme != NULL)
2371 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2372 xmlFreeURI(puri);
2373 }
Owen Taylor3473f882001-02-23 17:55:21 +00002374
2375 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002376 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002377 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002378 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002379 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002380 if (unescaped != NULL) {
2381#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002382 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002383 context = xmlGzfileOpenW(unescaped, compression);
2384 if (context != NULL) {
2385 ret = xmlAllocOutputBuffer(encoder);
2386 if (ret != NULL) {
2387 ret->context = context;
2388 ret->writecallback = xmlGzfileWrite;
2389 ret->closecallback = xmlGzfileClose;
2390 }
2391 xmlFree(unescaped);
2392 return(ret);
2393 }
2394 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002395#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002396 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2397 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2398 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2399#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2400 /* Need to pass compression parameter into HTTP open calls */
2401 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2402 context = xmlIOHTTPOpenW(unescaped, compression);
2403 else
2404#endif
2405 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2406 if (context != NULL)
2407 break;
2408 }
2409 }
2410 xmlFree(unescaped);
2411 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002412
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002413 /*
2414 * If this failed try with a non-escaped URI this may be a strange
2415 * filename
2416 */
2417 if (context == NULL) {
2418#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002419 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002420 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002421 if (context != NULL) {
2422 ret = xmlAllocOutputBuffer(encoder);
2423 if (ret != NULL) {
2424 ret->context = context;
2425 ret->writecallback = xmlGzfileWrite;
2426 ret->closecallback = xmlGzfileClose;
2427 }
2428 return(ret);
2429 }
2430 }
2431#endif
2432 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2433 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002434 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002435#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2436 /* Need to pass compression parameter into HTTP open calls */
2437 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2438 context = xmlIOHTTPOpenW(URI, compression);
2439 else
2440#endif
2441 context = xmlOutputCallbackTable[i].opencallback(URI);
2442 if (context != NULL)
2443 break;
2444 }
Owen Taylor3473f882001-02-23 17:55:21 +00002445 }
2446 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002447
Owen Taylor3473f882001-02-23 17:55:21 +00002448 if (context == NULL) {
2449 return(NULL);
2450 }
2451
2452 /*
2453 * Allocate the Output buffer front-end.
2454 */
2455 ret = xmlAllocOutputBuffer(encoder);
2456 if (ret != NULL) {
2457 ret->context = context;
2458 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2459 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2460 }
2461 return(ret);
2462}
Daniel Veillard0335a842004-06-02 16:18:40 +00002463
2464/**
2465 * xmlOutputBufferCreateFilename:
2466 * @URI: a C string containing the URI or filename
2467 * @encoder: the encoding converter or NULL
2468 * @compression: the compression ration (0 none, 9 max).
2469 *
2470 * Create a buffered output for the progressive saving of a file
2471 * If filename is "-' then we use stdout as the output.
2472 * Automatic support for ZLIB/Compress compressed document is provided
2473 * by default if found at compile-time.
2474 * TODO: currently if compression is set, the library only support
2475 * writing to a local file.
2476 *
2477 * Returns the new output or NULL
2478 */
2479xmlOutputBufferPtr
2480xmlOutputBufferCreateFilename(const char *URI,
2481 xmlCharEncodingHandlerPtr encoder,
2482 int compression ATTRIBUTE_UNUSED) {
2483 if ((xmlOutputBufferCreateFilenameValue)) {
2484 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2485 }
2486 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2487}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002488#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002489
2490/**
2491 * xmlParserInputBufferCreateFile:
2492 * @file: a FILE*
2493 * @enc: the charset encoding if known
2494 *
2495 * Create a buffered parser input for the progressive parsing of a FILE *
2496 * buffered C I/O
2497 *
2498 * Returns the new parser input or NULL
2499 */
2500xmlParserInputBufferPtr
2501xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2502 xmlParserInputBufferPtr ret;
2503
2504 if (xmlInputCallbackInitialized == 0)
2505 xmlRegisterDefaultInputCallbacks();
2506
2507 if (file == NULL) return(NULL);
2508
2509 ret = xmlAllocParserInputBuffer(enc);
2510 if (ret != NULL) {
2511 ret->context = file;
2512 ret->readcallback = xmlFileRead;
2513 ret->closecallback = xmlFileFlush;
2514 }
2515
2516 return(ret);
2517}
2518
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002519#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002520/**
2521 * xmlOutputBufferCreateFile:
2522 * @file: a FILE*
2523 * @encoder: the encoding converter or NULL
2524 *
2525 * Create a buffered output for the progressive saving to a FILE *
2526 * buffered C I/O
2527 *
2528 * Returns the new parser output or NULL
2529 */
2530xmlOutputBufferPtr
2531xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2532 xmlOutputBufferPtr ret;
2533
2534 if (xmlOutputCallbackInitialized == 0)
2535 xmlRegisterDefaultOutputCallbacks();
2536
2537 if (file == NULL) return(NULL);
2538
2539 ret = xmlAllocOutputBuffer(encoder);
2540 if (ret != NULL) {
2541 ret->context = file;
2542 ret->writecallback = xmlFileWrite;
2543 ret->closecallback = xmlFileFlush;
2544 }
2545
2546 return(ret);
2547}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002548
2549/**
2550 * xmlOutputBufferCreateBuffer:
2551 * @buffer: a xmlBufferPtr
2552 * @encoder: the encoding converter or NULL
2553 *
2554 * Create a buffered output for the progressive saving to a xmlBuffer
2555 *
2556 * Returns the new parser output or NULL
2557 */
2558xmlOutputBufferPtr
2559xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2560 xmlCharEncodingHandlerPtr encoder) {
2561 xmlOutputBufferPtr ret;
2562
2563 if (buffer == NULL) return(NULL);
2564
Rob Richardsa44f2342005-11-09 18:03:45 +00002565 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2566 xmlBufferWrite,
2567 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002568 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002569
2570 return(ret);
2571}
2572
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002573#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002574
2575/**
2576 * xmlParserInputBufferCreateFd:
2577 * @fd: a file descriptor number
2578 * @enc: the charset encoding if known
2579 *
2580 * Create a buffered parser input for the progressive parsing for the input
2581 * from a file descriptor
2582 *
2583 * Returns the new parser input or NULL
2584 */
2585xmlParserInputBufferPtr
2586xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2587 xmlParserInputBufferPtr ret;
2588
2589 if (fd < 0) return(NULL);
2590
2591 ret = xmlAllocParserInputBuffer(enc);
2592 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002593 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002594 ret->readcallback = xmlFdRead;
2595 ret->closecallback = xmlFdClose;
2596 }
2597
2598 return(ret);
2599}
2600
2601/**
2602 * xmlParserInputBufferCreateMem:
2603 * @mem: the memory input
2604 * @size: the length of the memory block
2605 * @enc: the charset encoding if known
2606 *
2607 * Create a buffered parser input for the progressive parsing for the input
2608 * from a memory area.
2609 *
2610 * Returns the new parser input or NULL
2611 */
2612xmlParserInputBufferPtr
2613xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2614 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002615 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002616
2617 if (size <= 0) return(NULL);
2618 if (mem == NULL) return(NULL);
2619
2620 ret = xmlAllocParserInputBuffer(enc);
2621 if (ret != NULL) {
2622 ret->context = (void *) mem;
2623 ret->readcallback = (xmlInputReadCallback) xmlNop;
2624 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002625 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2626 if (errcode != 0) {
2627 xmlFree(ret);
2628 return(NULL);
2629 }
Owen Taylor3473f882001-02-23 17:55:21 +00002630 }
2631
2632 return(ret);
2633}
2634
2635/**
Daniel Veillard53350552003-09-18 13:35:51 +00002636 * xmlParserInputBufferCreateStatic:
2637 * @mem: the memory input
2638 * @size: the length of the memory block
2639 * @enc: the charset encoding if known
2640 *
2641 * Create a buffered parser input for the progressive parsing for the input
2642 * from an immutable memory area. This will not copy the memory area to
2643 * the buffer, but the memory is expected to be available until the end of
2644 * the parsing, this is useful for example when using mmap'ed file.
2645 *
2646 * Returns the new parser input or NULL
2647 */
2648xmlParserInputBufferPtr
2649xmlParserInputBufferCreateStatic(const char *mem, int size,
2650 xmlCharEncoding enc) {
2651 xmlParserInputBufferPtr ret;
2652
2653 if (size <= 0) return(NULL);
2654 if (mem == NULL) return(NULL);
2655
2656 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2657 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002658 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002659 return(NULL);
2660 }
2661 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002662 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002663 if (ret->buffer == NULL) {
2664 xmlFree(ret);
2665 return(NULL);
2666 }
2667 ret->encoder = xmlGetCharEncodingHandler(enc);
2668 if (ret->encoder != NULL)
2669 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2670 else
2671 ret->raw = NULL;
2672 ret->compressed = -1;
2673 ret->context = (void *) mem;
2674 ret->readcallback = NULL;
2675 ret->closecallback = NULL;
2676
2677 return(ret);
2678}
2679
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002680#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002681/**
Owen Taylor3473f882001-02-23 17:55:21 +00002682 * xmlOutputBufferCreateFd:
2683 * @fd: a file descriptor number
2684 * @encoder: the encoding converter or NULL
2685 *
2686 * Create a buffered output for the progressive saving
2687 * to a file descriptor
2688 *
2689 * Returns the new parser output or NULL
2690 */
2691xmlOutputBufferPtr
2692xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2693 xmlOutputBufferPtr ret;
2694
2695 if (fd < 0) return(NULL);
2696
2697 ret = xmlAllocOutputBuffer(encoder);
2698 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002699 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002700 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002701 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002702 }
2703
2704 return(ret);
2705}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002706#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002707
2708/**
2709 * xmlParserInputBufferCreateIO:
2710 * @ioread: an I/O read function
2711 * @ioclose: an I/O close function
2712 * @ioctx: an I/O handler
2713 * @enc: the charset encoding if known
2714 *
2715 * Create a buffered parser input for the progressive parsing for the input
2716 * from an I/O handler
2717 *
2718 * Returns the new parser input or NULL
2719 */
2720xmlParserInputBufferPtr
2721xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2722 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2723 xmlParserInputBufferPtr ret;
2724
2725 if (ioread == NULL) return(NULL);
2726
2727 ret = xmlAllocParserInputBuffer(enc);
2728 if (ret != NULL) {
2729 ret->context = (void *) ioctx;
2730 ret->readcallback = ioread;
2731 ret->closecallback = ioclose;
2732 }
2733
2734 return(ret);
2735}
2736
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002737#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002738/**
2739 * xmlOutputBufferCreateIO:
2740 * @iowrite: an I/O write function
2741 * @ioclose: an I/O close function
2742 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002743 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002744 *
2745 * Create a buffered output for the progressive saving
2746 * to an I/O handler
2747 *
2748 * Returns the new parser output or NULL
2749 */
2750xmlOutputBufferPtr
2751xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2752 xmlOutputCloseCallback ioclose, void *ioctx,
2753 xmlCharEncodingHandlerPtr encoder) {
2754 xmlOutputBufferPtr ret;
2755
2756 if (iowrite == NULL) return(NULL);
2757
2758 ret = xmlAllocOutputBuffer(encoder);
2759 if (ret != NULL) {
2760 ret->context = (void *) ioctx;
2761 ret->writecallback = iowrite;
2762 ret->closecallback = ioclose;
2763 }
2764
2765 return(ret);
2766}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002767#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002768
2769/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002770 * xmlParserInputBufferCreateFilenameDefault:
2771 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2772 *
2773 * Registers a callback for URI input file handling
2774 *
2775 * Returns the old value of the registration function
2776 */
2777xmlParserInputBufferCreateFilenameFunc
2778xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2779{
2780 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2781 if (old == NULL) {
2782 old = __xmlParserInputBufferCreateFilename;
2783 }
2784
2785 xmlParserInputBufferCreateFilenameValue = func;
2786 return(old);
2787}
2788
2789/**
2790 * xmlOutputBufferCreateFilenameDefault:
2791 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2792 *
2793 * Registers a callback for URI output file handling
2794 *
2795 * Returns the old value of the registration function
2796 */
2797xmlOutputBufferCreateFilenameFunc
2798xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2799{
2800 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2801#ifdef LIBXML_OUTPUT_ENABLED
2802 if (old == NULL) {
2803 old = __xmlOutputBufferCreateFilename;
2804 }
2805#endif
2806 xmlOutputBufferCreateFilenameValue = func;
2807 return(old);
2808}
2809
2810/**
Owen Taylor3473f882001-02-23 17:55:21 +00002811 * xmlParserInputBufferPush:
2812 * @in: a buffered parser input
2813 * @len: the size in bytes of the array.
2814 * @buf: an char array
2815 *
2816 * Push the content of the arry in the input buffer
2817 * This routine handle the I18N transcoding to internal UTF-8
2818 * This is used when operating the parser in progressive (push) mode.
2819 *
2820 * Returns the number of chars read and stored in the buffer, or -1
2821 * in case of error.
2822 */
2823int
2824xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2825 int len, const char *buf) {
2826 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002827 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002828
2829 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002830 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002831 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002832 unsigned int use;
2833
Owen Taylor3473f882001-02-23 17:55:21 +00002834 /*
2835 * Store the data in the incoming raw buffer
2836 */
2837 if (in->raw == NULL) {
2838 in->raw = xmlBufferCreate();
2839 }
William M. Bracka3215c72004-07-31 16:24:01 +00002840 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2841 if (ret != 0)
2842 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002843
2844 /*
2845 * convert as much as possible to the parser reading buffer.
2846 */
Daniel Veillard36711902004-02-11 13:25:26 +00002847 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002848 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2849 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002850 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002851 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002852 return(-1);
2853 }
Daniel Veillard36711902004-02-11 13:25:26 +00002854 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002855 } else {
2856 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002857 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2858 if (ret != 0)
2859 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002860 }
2861#ifdef DEBUG_INPUT
2862 xmlGenericError(xmlGenericErrorContext,
2863 "I/O: pushed %d chars, buffer %d/%d\n",
2864 nbchars, in->buffer->use, in->buffer->size);
2865#endif
2866 return(nbchars);
2867}
2868
2869/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002870 * endOfInput:
2871 *
2872 * When reading from an Input channel indicated end of file or error
2873 * don't reread from it again.
2874 */
2875static int
2876endOfInput (void * context ATTRIBUTE_UNUSED,
2877 char * buffer ATTRIBUTE_UNUSED,
2878 int len ATTRIBUTE_UNUSED) {
2879 return(0);
2880}
2881
2882/**
Owen Taylor3473f882001-02-23 17:55:21 +00002883 * xmlParserInputBufferGrow:
2884 * @in: a buffered parser input
2885 * @len: indicative value of the amount of chars to read
2886 *
2887 * Grow up the content of the input buffer, the old data are preserved
2888 * This routine handle the I18N transcoding to internal UTF-8
2889 * This routine is used when operating the parser in normal (pull) mode
2890 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002891 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002892 * onto in->buffer or in->raw
2893 *
2894 * Returns the number of chars read and stored in the buffer, or -1
2895 * in case of error.
2896 */
2897int
2898xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2899 char *buffer = NULL;
2900 int res = 0;
2901 int nbchars = 0;
2902 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002903 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002904
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002905 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002906 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002907 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002908
Owen Taylor3473f882001-02-23 17:55:21 +00002909 buffree = in->buffer->size - in->buffer->use;
2910 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002911 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002912 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002913 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002914 }
Owen Taylor3473f882001-02-23 17:55:21 +00002915
Daniel Veillarde5354492002-05-16 08:43:22 +00002916 needSize = in->buffer->use + len + 1;
2917 if (needSize > in->buffer->size){
2918 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002919 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002920 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002921 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002922 }
Owen Taylor3473f882001-02-23 17:55:21 +00002923 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002924 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002925
2926 /*
2927 * Call the read method for this I/O type.
2928 */
2929 if (in->readcallback != NULL) {
2930 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002931 if (res <= 0)
2932 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002933 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002934 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002935 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002936 return(-1);
2937 }
2938 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002939 return(-1);
2940 }
2941 len = res;
2942 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002943 unsigned int use;
2944
Owen Taylor3473f882001-02-23 17:55:21 +00002945 /*
2946 * Store the data in the incoming raw buffer
2947 */
2948 if (in->raw == NULL) {
2949 in->raw = xmlBufferCreate();
2950 }
William M. Bracka3215c72004-07-31 16:24:01 +00002951 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2952 if (res != 0)
2953 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002954
2955 /*
2956 * convert as much as possible to the parser reading buffer.
2957 */
Daniel Veillard36711902004-02-11 13:25:26 +00002958 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002959 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2960 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002961 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002962 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002963 return(-1);
2964 }
Daniel Veillard36711902004-02-11 13:25:26 +00002965 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002966 } else {
2967 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002968 in->buffer->use += nbchars;
2969 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002970 }
2971#ifdef DEBUG_INPUT
2972 xmlGenericError(xmlGenericErrorContext,
2973 "I/O: read %d chars, buffer %d/%d\n",
2974 nbchars, in->buffer->use, in->buffer->size);
2975#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002976 return(nbchars);
2977}
2978
2979/**
2980 * xmlParserInputBufferRead:
2981 * @in: a buffered parser input
2982 * @len: indicative value of the amount of chars to read
2983 *
2984 * Refresh the content of the input buffer, the old data are considered
2985 * consumed
2986 * This routine handle the I18N transcoding to internal UTF-8
2987 *
2988 * Returns the number of chars read and stored in the buffer, or -1
2989 * in case of error.
2990 */
2991int
2992xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002993 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002994 if (in->readcallback != NULL)
2995 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002996 else if ((in->buffer != NULL) &&
2997 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2998 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002999 else
3000 return(-1);
3001}
3002
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003003#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003004/**
3005 * xmlOutputBufferWrite:
3006 * @out: a buffered parser output
3007 * @len: the size in bytes of the array.
3008 * @buf: an char array
3009 *
3010 * Write the content of the array in the output I/O buffer
3011 * This routine handle the I18N transcoding from internal UTF-8
3012 * The buffer is lossless, i.e. will store in case of partial
3013 * or delayed writes.
3014 *
3015 * Returns the number of chars immediately written, or -1
3016 * in case of error.
3017 */
3018int
3019xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3020 int nbchars = 0; /* number of chars to output to I/O */
3021 int ret; /* return from function call */
3022 int written = 0; /* number of char written to I/O so far */
3023 int chunk; /* number of byte curreent processed from buf */
3024
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003025 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003026 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003027 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003028
3029 do {
3030 chunk = len;
3031 if (chunk > 4 * MINLEN)
3032 chunk = 4 * MINLEN;
3033
3034 /*
3035 * first handle encoding stuff.
3036 */
3037 if (out->encoder != NULL) {
3038 /*
3039 * Store the data in the incoming raw buffer
3040 */
3041 if (out->conv == NULL) {
3042 out->conv = xmlBufferCreate();
3043 }
William M. Bracka3215c72004-07-31 16:24:01 +00003044 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3045 if (ret != 0)
3046 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003047
3048 if ((out->buffer->use < MINLEN) && (chunk == len))
3049 goto done;
3050
3051 /*
3052 * convert as much as possible to the parser reading buffer.
3053 */
3054 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003055 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003056 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003057 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003058 return(-1);
3059 }
3060 nbchars = out->conv->use;
3061 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003062 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3063 if (ret != 0)
3064 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003065 nbchars = out->buffer->use;
3066 }
3067 buf += chunk;
3068 len -= chunk;
3069
3070 if ((nbchars < MINLEN) && (len <= 0))
3071 goto done;
3072
3073 if (out->writecallback) {
3074 /*
3075 * second write the stuff to the I/O channel
3076 */
3077 if (out->encoder != NULL) {
3078 ret = out->writecallback(out->context,
3079 (const char *)out->conv->content, nbchars);
3080 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003081 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003082 } else {
3083 ret = out->writecallback(out->context,
3084 (const char *)out->buffer->content, nbchars);
3085 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003086 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003087 }
3088 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003089 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003090 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003091 return(ret);
3092 }
3093 out->written += ret;
3094 }
3095 written += nbchars;
3096 } while (len > 0);
3097
3098done:
3099#ifdef DEBUG_INPUT
3100 xmlGenericError(xmlGenericErrorContext,
3101 "I/O: wrote %d chars\n", written);
3102#endif
3103 return(written);
3104}
3105
3106/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003107 * xmlEscapeContent:
3108 * @out: a pointer to an array of bytes to store the result
3109 * @outlen: the length of @out
3110 * @in: a pointer to an array of unescaped UTF-8 bytes
3111 * @inlen: the length of @in
3112 *
3113 * Take a block of UTF-8 chars in and escape them.
3114 * Returns 0 if success, or -1 otherwise
3115 * The value of @inlen after return is the number of octets consumed
3116 * if the return value is positive, else unpredictable.
3117 * The value of @outlen after return is the number of octets consumed.
3118 */
3119static int
3120xmlEscapeContent(unsigned char* out, int *outlen,
3121 const xmlChar* in, int *inlen) {
3122 unsigned char* outstart = out;
3123 const unsigned char* base = in;
3124 unsigned char* outend = out + *outlen;
3125 const unsigned char* inend;
3126
3127 inend = in + (*inlen);
3128
3129 while ((in < inend) && (out < outend)) {
3130 if (*in == '<') {
3131 if (outend - out < 4) break;
3132 *out++ = '&';
3133 *out++ = 'l';
3134 *out++ = 't';
3135 *out++ = ';';
3136 } else if (*in == '>') {
3137 if (outend - out < 4) break;
3138 *out++ = '&';
3139 *out++ = 'g';
3140 *out++ = 't';
3141 *out++ = ';';
3142 } else if (*in == '&') {
3143 if (outend - out < 5) break;
3144 *out++ = '&';
3145 *out++ = 'a';
3146 *out++ = 'm';
3147 *out++ = 'p';
3148 *out++ = ';';
3149 } else if (*in == '\r') {
3150 if (outend - out < 5) break;
3151 *out++ = '&';
3152 *out++ = '#';
3153 *out++ = '1';
3154 *out++ = '3';
3155 *out++ = ';';
3156 } else {
3157 *out++ = (unsigned char) *in;
3158 }
3159 ++in;
3160 }
3161 *outlen = out - outstart;
3162 *inlen = in - base;
3163 return(0);
3164}
3165
3166/**
3167 * xmlOutputBufferWriteEscape:
3168 * @out: a buffered parser output
3169 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003170 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003171 *
3172 * Write the content of the string in the output I/O buffer
3173 * This routine escapes the caracters and then handle the I18N
3174 * transcoding from internal UTF-8
3175 * The buffer is lossless, i.e. will store in case of partial
3176 * or delayed writes.
3177 *
3178 * Returns the number of chars immediately written, or -1
3179 * in case of error.
3180 */
3181int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003182xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3183 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003184 int nbchars = 0; /* number of chars to output to I/O */
3185 int ret; /* return from function call */
3186 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003187 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003188 int chunk; /* number of byte currently processed from str */
3189 int len; /* number of bytes in str */
3190 int cons; /* byte from str consumed */
3191
Daniel Veillardce244ad2004-11-05 10:03:46 +00003192 if ((out == NULL) || (out->error) || (str == NULL) ||
3193 (out->buffer == NULL) ||
3194 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003195 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003196 if (len < 0) return(0);
3197 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003198 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003199
3200 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003201 oldwritten = written;
3202
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003203 /*
3204 * how many bytes to consume and how many bytes to store.
3205 */
3206 cons = len;
3207 chunk = (out->buffer->size - out->buffer->use) - 1;
3208
3209 /*
3210 * first handle encoding stuff.
3211 */
3212 if (out->encoder != NULL) {
3213 /*
3214 * Store the data in the incoming raw buffer
3215 */
3216 if (out->conv == NULL) {
3217 out->conv = xmlBufferCreate();
3218 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003219 ret = escaping(out->buffer->content + out->buffer->use ,
3220 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003221 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003222 return(-1);
3223 out->buffer->use += chunk;
3224 out->buffer->content[out->buffer->use] = 0;
3225
3226 if ((out->buffer->use < MINLEN) && (cons == len))
3227 goto done;
3228
3229 /*
3230 * convert as much as possible to the output buffer.
3231 */
3232 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3233 if ((ret < 0) && (ret != -3)) {
3234 xmlIOErr(XML_IO_ENCODER, NULL);
3235 out->error = XML_IO_ENCODER;
3236 return(-1);
3237 }
3238 nbchars = out->conv->use;
3239 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003240 ret = escaping(out->buffer->content + out->buffer->use ,
3241 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003242 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003243 return(-1);
3244 out->buffer->use += chunk;
3245 out->buffer->content[out->buffer->use] = 0;
3246 nbchars = out->buffer->use;
3247 }
3248 str += cons;
3249 len -= cons;
3250
3251 if ((nbchars < MINLEN) && (len <= 0))
3252 goto done;
3253
3254 if (out->writecallback) {
3255 /*
3256 * second write the stuff to the I/O channel
3257 */
3258 if (out->encoder != NULL) {
3259 ret = out->writecallback(out->context,
3260 (const char *)out->conv->content, nbchars);
3261 if (ret >= 0)
3262 xmlBufferShrink(out->conv, ret);
3263 } else {
3264 ret = out->writecallback(out->context,
3265 (const char *)out->buffer->content, nbchars);
3266 if (ret >= 0)
3267 xmlBufferShrink(out->buffer, ret);
3268 }
3269 if (ret < 0) {
3270 xmlIOErr(XML_IO_WRITE, NULL);
3271 out->error = XML_IO_WRITE;
3272 return(ret);
3273 }
3274 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003275 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3276 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003277 }
3278 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003279 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003280
3281done:
3282#ifdef DEBUG_INPUT
3283 xmlGenericError(xmlGenericErrorContext,
3284 "I/O: wrote %d chars\n", written);
3285#endif
3286 return(written);
3287}
3288
3289/**
Owen Taylor3473f882001-02-23 17:55:21 +00003290 * xmlOutputBufferWriteString:
3291 * @out: a buffered parser output
3292 * @str: a zero terminated C string
3293 *
3294 * Write the content of the string in the output I/O buffer
3295 * This routine handle the I18N transcoding from internal UTF-8
3296 * The buffer is lossless, i.e. will store in case of partial
3297 * or delayed writes.
3298 *
3299 * Returns the number of chars immediately written, or -1
3300 * in case of error.
3301 */
3302int
3303xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3304 int len;
3305
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003306 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003307 if (str == NULL)
3308 return(-1);
3309 len = strlen(str);
3310
3311 if (len > 0)
3312 return(xmlOutputBufferWrite(out, len, str));
3313 return(len);
3314}
3315
3316/**
3317 * xmlOutputBufferFlush:
3318 * @out: a buffered output
3319 *
3320 * flushes the output I/O channel
3321 *
3322 * Returns the number of byte written or -1 in case of error.
3323 */
3324int
3325xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3326 int nbchars = 0, ret = 0;
3327
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003328 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003329 /*
3330 * first handle encoding stuff.
3331 */
3332 if ((out->conv != NULL) && (out->encoder != NULL)) {
3333 /*
3334 * convert as much as possible to the parser reading buffer.
3335 */
3336 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3337 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003338 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003339 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003340 return(-1);
3341 }
3342 }
3343
3344 /*
3345 * second flush the stuff to the I/O channel
3346 */
3347 if ((out->conv != NULL) && (out->encoder != NULL) &&
3348 (out->writecallback != NULL)) {
3349 ret = out->writecallback(out->context,
3350 (const char *)out->conv->content, out->conv->use);
3351 if (ret >= 0)
3352 xmlBufferShrink(out->conv, ret);
3353 } else if (out->writecallback != NULL) {
3354 ret = out->writecallback(out->context,
3355 (const char *)out->buffer->content, out->buffer->use);
3356 if (ret >= 0)
3357 xmlBufferShrink(out->buffer, ret);
3358 }
3359 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003360 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003361 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003362 return(ret);
3363 }
3364 out->written += ret;
3365
3366#ifdef DEBUG_INPUT
3367 xmlGenericError(xmlGenericErrorContext,
3368 "I/O: flushed %d chars\n", ret);
3369#endif
3370 return(ret);
3371}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003372#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003373
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003374/**
Owen Taylor3473f882001-02-23 17:55:21 +00003375 * xmlParserGetDirectory:
3376 * @filename: the path to a file
3377 *
3378 * lookup the directory for that file
3379 *
3380 * Returns a new allocated string containing the directory, or NULL.
3381 */
3382char *
3383xmlParserGetDirectory(const char *filename) {
3384 char *ret = NULL;
3385 char dir[1024];
3386 char *cur;
3387 char sep = '/';
3388
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003389#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3390 return NULL;
3391#endif
3392
Owen Taylor3473f882001-02-23 17:55:21 +00003393 if (xmlInputCallbackInitialized == 0)
3394 xmlRegisterDefaultInputCallbacks();
3395
3396 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003397#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003398 sep = '\\';
3399#endif
3400
3401 strncpy(dir, filename, 1023);
3402 dir[1023] = 0;
3403 cur = &dir[strlen(dir)];
3404 while (cur > dir) {
3405 if (*cur == sep) break;
3406 cur --;
3407 }
3408 if (*cur == sep) {
3409 if (cur == dir) dir[1] = 0;
3410 else *cur = 0;
3411 ret = xmlMemStrdup(dir);
3412 } else {
3413 if (getcwd(dir, 1024) != NULL) {
3414 dir[1023] = 0;
3415 ret = xmlMemStrdup(dir);
3416 }
3417 }
3418 return(ret);
3419}
3420
3421/****************************************************************
3422 * *
3423 * External entities loading *
3424 * *
3425 ****************************************************************/
3426
Daniel Veillarda840b692003-10-19 13:35:37 +00003427/**
3428 * xmlCheckHTTPInput:
3429 * @ctxt: an XML parser context
3430 * @ret: an XML parser input
3431 *
3432 * Check an input in case it was created from an HTTP stream, in that
3433 * case it will handle encoding and update of the base URL in case of
3434 * redirection. It also checks for HTTP errors in which case the input
3435 * is cleanly freed up and an appropriate error is raised in context
3436 *
3437 * Returns the input or NULL in case of HTTP error.
3438 */
3439xmlParserInputPtr
3440xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3441#ifdef LIBXML_HTTP_ENABLED
3442 if ((ret != NULL) && (ret->buf != NULL) &&
3443 (ret->buf->readcallback == xmlIOHTTPRead) &&
3444 (ret->buf->context != NULL)) {
3445 const char *encoding;
3446 const char *redir;
3447 const char *mime;
3448 int code;
3449
3450 code = xmlNanoHTTPReturnCode(ret->buf->context);
3451 if (code >= 400) {
3452 /* fatal error */
3453 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003454 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003455 (const char *) ret->filename);
3456 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003457 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003458 xmlFreeInputStream(ret);
3459 ret = NULL;
3460 } else {
3461
3462 mime = xmlNanoHTTPMimeType(ret->buf->context);
3463 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3464 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3465 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3466 if (encoding != NULL) {
3467 xmlCharEncodingHandlerPtr handler;
3468
3469 handler = xmlFindCharEncodingHandler(encoding);
3470 if (handler != NULL) {
3471 xmlSwitchInputEncoding(ctxt, ret, handler);
3472 } else {
3473 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3474 "Unknown encoding %s",
3475 BAD_CAST encoding, NULL);
3476 }
3477 if (ret->encoding == NULL)
3478 ret->encoding = xmlStrdup(BAD_CAST encoding);
3479 }
3480#if 0
3481 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3482#endif
3483 }
3484 redir = xmlNanoHTTPRedir(ret->buf->context);
3485 if (redir != NULL) {
3486 if (ret->filename != NULL)
3487 xmlFree((xmlChar *) ret->filename);
3488 if (ret->directory != NULL) {
3489 xmlFree((xmlChar *) ret->directory);
3490 ret->directory = NULL;
3491 }
3492 ret->filename =
3493 (char *) xmlStrdup((const xmlChar *) redir);
3494 }
3495 }
3496 }
3497#endif
3498 return(ret);
3499}
3500
Daniel Veillard561b7f82002-03-20 21:55:57 +00003501static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003502#ifdef HAVE_STAT
3503 int ret;
3504 struct stat info;
3505 const char *path;
3506
3507 if (URL == NULL)
3508 return(0);
3509
Daniel Veillardf4862f02002-09-10 11:13:43 +00003510 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003511#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003512 path = &URL[17];
3513#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003514 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003515#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003516 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003517#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003518 path = &URL[8];
3519#else
3520 path = &URL[7];
3521#endif
3522 } else
3523 path = URL;
3524 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003525 if (ret == 0)
3526 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003527#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003528 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003529}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003530
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003531/**
Owen Taylor3473f882001-02-23 17:55:21 +00003532 * xmlDefaultExternalEntityLoader:
3533 * @URL: the URL for the entity to load
3534 * @ID: the System ID for the entity to load
3535 * @ctxt: the context in which the entity is called or NULL
3536 *
3537 * By default we don't load external entitites, yet.
3538 *
3539 * Returns a new allocated xmlParserInputPtr, or NULL.
3540 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003541static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003542xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003543 xmlParserCtxtPtr ctxt)
3544{
Owen Taylor3473f882001-02-23 17:55:21 +00003545 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003546 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003547
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003548#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003549 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003550#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003551
3552#ifdef DEBUG_EXTERNAL_ENTITIES
3553 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003554 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003555#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003556#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003557 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3558 int options = ctxt->options;
3559
3560 ctxt->options -= XML_PARSE_NONET;
3561 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3562 ctxt->options = options;
3563 return(ret);
3564 }
3565
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003566 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003567 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003568 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003569 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003570 pref = xmlCatalogGetDefaults();
3571
Daniel Veillard561b7f82002-03-20 21:55:57 +00003572 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003573 /*
3574 * Do a local lookup
3575 */
Daniel Veillard42595322004-11-08 10:52:06 +00003576 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003577 ((pref == XML_CATA_ALLOW_ALL) ||
3578 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3579 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3580 (const xmlChar *) ID,
3581 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003582 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003583 /*
3584 * Try a global lookup
3585 */
3586 if ((resource == NULL) &&
3587 ((pref == XML_CATA_ALLOW_ALL) ||
3588 (pref == XML_CATA_ALLOW_GLOBAL))) {
3589 resource = xmlCatalogResolve((const xmlChar *) ID,
3590 (const xmlChar *) URL);
3591 }
3592 if ((resource == NULL) && (URL != NULL))
3593 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003594
Daniel Veillarda840b692003-10-19 13:35:37 +00003595 /*
3596 * TODO: do an URI lookup on the reference
3597 */
3598 if ((resource != NULL)
3599 && (!xmlSysIDExists((const char *) resource))) {
3600 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003601
Daniel Veillard42595322004-11-08 10:52:06 +00003602 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003603 ((pref == XML_CATA_ALLOW_ALL) ||
3604 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3605 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3606 }
3607 if ((tmp == NULL) &&
3608 ((pref == XML_CATA_ALLOW_ALL) ||
3609 (pref == XML_CATA_ALLOW_GLOBAL))) {
3610 tmp = xmlCatalogResolveURI(resource);
3611 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003612
Daniel Veillarda840b692003-10-19 13:35:37 +00003613 if (tmp != NULL) {
3614 xmlFree(resource);
3615 resource = tmp;
3616 }
3617 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003618 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003619#endif
3620
3621 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003622 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003623
3624 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003625 if (ID == NULL)
3626 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003627 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003628 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003629 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003630 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003631 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003632 xmlFree(resource);
3633 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003634}
3635
3636static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3637 xmlDefaultExternalEntityLoader;
3638
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003639/**
Owen Taylor3473f882001-02-23 17:55:21 +00003640 * xmlSetExternalEntityLoader:
3641 * @f: the new entity resolver function
3642 *
3643 * Changes the defaultexternal entity resolver function for the application
3644 */
3645void
3646xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3647 xmlCurrentExternalEntityLoader = f;
3648}
3649
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003650/**
Owen Taylor3473f882001-02-23 17:55:21 +00003651 * xmlGetExternalEntityLoader:
3652 *
3653 * Get the default external entity resolver function for the application
3654 *
3655 * Returns the xmlExternalEntityLoader function pointer
3656 */
3657xmlExternalEntityLoader
3658xmlGetExternalEntityLoader(void) {
3659 return(xmlCurrentExternalEntityLoader);
3660}
3661
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003662/**
Owen Taylor3473f882001-02-23 17:55:21 +00003663 * xmlLoadExternalEntity:
3664 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003665 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003666 * @ctxt: the context in which the entity is called or NULL
3667 *
3668 * Load an external entity, note that the use of this function for
3669 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003670 *
3671 * Returns the xmlParserInputPtr or NULL
3672 */
3673xmlParserInputPtr
3674xmlLoadExternalEntity(const char *URL, const char *ID,
3675 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003676 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3677 char *canonicFilename;
3678 xmlParserInputPtr ret;
3679
3680 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3681 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003682 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003683 return(NULL);
3684 }
3685
3686 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3687 xmlFree(canonicFilename);
3688 return(ret);
3689 }
Owen Taylor3473f882001-02-23 17:55:21 +00003690 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3691}
3692
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003693/************************************************************************
3694 * *
3695 * Disabling Network access *
3696 * *
3697 ************************************************************************/
3698
3699#ifdef LIBXML_CATALOG_ENABLED
3700static int
3701xmlNoNetExists(const char *URL)
3702{
3703#ifdef HAVE_STAT
3704 int ret;
3705 struct stat info;
3706 const char *path;
3707
3708 if (URL == NULL)
3709 return (0);
3710
Daniel Veillardf4862f02002-09-10 11:13:43 +00003711 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003712#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003713 path = &URL[17];
3714#else
3715 path = &URL[16];
3716#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003717 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003718#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003719 path = &URL[8];
3720#else
3721 path = &URL[7];
3722#endif
3723 } else
3724 path = URL;
3725 ret = stat(path, &info);
3726 if (ret == 0)
3727 return (1);
3728#endif
3729 return (0);
3730}
3731#endif
3732
3733/**
3734 * xmlNoNetExternalEntityLoader:
3735 * @URL: the URL for the entity to load
3736 * @ID: the System ID for the entity to load
3737 * @ctxt: the context in which the entity is called or NULL
3738 *
3739 * A specific entity loader disabling network accesses, though still
3740 * allowing local catalog accesses for resolution.
3741 *
3742 * Returns a new allocated xmlParserInputPtr, or NULL.
3743 */
3744xmlParserInputPtr
3745xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3746 xmlParserCtxtPtr ctxt) {
3747 xmlParserInputPtr input = NULL;
3748 xmlChar *resource = NULL;
3749
3750#ifdef LIBXML_CATALOG_ENABLED
3751 xmlCatalogAllow pref;
3752
3753 /*
3754 * If the resource doesn't exists as a file,
3755 * try to load it from the resource pointed in the catalogs
3756 */
3757 pref = xmlCatalogGetDefaults();
3758
3759 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3760 /*
3761 * Do a local lookup
3762 */
Daniel Veillard42595322004-11-08 10:52:06 +00003763 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003764 ((pref == XML_CATA_ALLOW_ALL) ||
3765 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3766 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3767 (const xmlChar *)ID,
3768 (const xmlChar *)URL);
3769 }
3770 /*
3771 * Try a global lookup
3772 */
3773 if ((resource == NULL) &&
3774 ((pref == XML_CATA_ALLOW_ALL) ||
3775 (pref == XML_CATA_ALLOW_GLOBAL))) {
3776 resource = xmlCatalogResolve((const xmlChar *)ID,
3777 (const xmlChar *)URL);
3778 }
3779 if ((resource == NULL) && (URL != NULL))
3780 resource = xmlStrdup((const xmlChar *) URL);
3781
3782 /*
3783 * TODO: do an URI lookup on the reference
3784 */
3785 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3786 xmlChar *tmp = NULL;
3787
Daniel Veillard42595322004-11-08 10:52:06 +00003788 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003789 ((pref == XML_CATA_ALLOW_ALL) ||
3790 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3791 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3792 }
3793 if ((tmp == NULL) &&
3794 ((pref == XML_CATA_ALLOW_ALL) ||
3795 (pref == XML_CATA_ALLOW_GLOBAL))) {
3796 tmp = xmlCatalogResolveURI(resource);
3797 }
3798
3799 if (tmp != NULL) {
3800 xmlFree(resource);
3801 resource = tmp;
3802 }
3803 }
3804 }
3805#endif
3806 if (resource == NULL)
3807 resource = (xmlChar *) URL;
3808
3809 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003810 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3811 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003812 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003813 if (resource != (xmlChar *) URL)
3814 xmlFree(resource);
3815 return(NULL);
3816 }
3817 }
3818 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3819 if (resource != (xmlChar *) URL)
3820 xmlFree(resource);
3821 return(input);
3822}
3823
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003824#define bottom_xmlIO
3825#include "elfgcchack.h"