blob: 6642a599329abc8b43220e831f91519f3c728055 [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
39/* Figure a portable way to know if a file is a directory. */
40#ifndef HAVE_STAT
41# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000042 /* MS C library seems to define stat and _stat. The definition
43 is identical. Still, mapping them to each other causes a warning. */
44# ifndef _MSC_VER
45# define stat(x,y) _stat(x,y)
46# endif
Owen Taylor3473f882001-02-23 17:55:21 +000047# define HAVE_STAT
48# endif
49#endif
50#ifdef HAVE_STAT
51# ifndef S_ISDIR
52# ifdef _S_ISDIR
53# define S_ISDIR(x) _S_ISDIR(x)
54# else
55# ifdef S_IFDIR
56# ifndef S_IFMT
57# ifdef _S_IFMT
58# define S_IFMT _S_IFMT
59# endif
60# endif
61# ifdef S_IFMT
62# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
63# endif
64# endif
65# endif
66# endif
67#endif
68
69#include <libxml/xmlmemory.h>
70#include <libxml/parser.h>
71#include <libxml/parserInternals.h>
72#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000073#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000074#include <libxml/nanohttp.h>
75#include <libxml/nanoftp.h>
76#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000077#ifdef LIBXML_CATALOG_ENABLED
78#include <libxml/catalog.h>
79#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000080#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000081
Daniel Veillardf012a642001-07-23 19:10:52 +000082/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000083/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000084/* #define DEBUG_INPUT */
85
86#ifdef DEBUG_INPUT
87#define MINLEN 40
88#else
89#define MINLEN 4000
90#endif
91
92/*
93 * Input I/O callback sets
94 */
95typedef struct _xmlInputCallback {
96 xmlInputMatchCallback matchcallback;
97 xmlInputOpenCallback opencallback;
98 xmlInputReadCallback readcallback;
99 xmlInputCloseCallback closecallback;
100} xmlInputCallback;
101
102#define MAX_INPUT_CALLBACK 15
103
Daniel Veillard22090732001-07-16 00:06:07 +0000104static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
105static int xmlInputCallbackNr = 0;
106static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000107
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000108#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000109/*
110 * Output I/O callback sets
111 */
112typedef struct _xmlOutputCallback {
113 xmlOutputMatchCallback matchcallback;
114 xmlOutputOpenCallback opencallback;
115 xmlOutputWriteCallback writecallback;
116 xmlOutputCloseCallback closecallback;
117} xmlOutputCallback;
118
119#define MAX_OUTPUT_CALLBACK 15
120
Daniel Veillard22090732001-07-16 00:06:07 +0000121static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
122static int xmlOutputCallbackNr = 0;
123static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000124#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Daniel Veillard05d987b2003-10-08 11:54:57 +0000126/************************************************************************
127 * *
128 * Tree memory error handler *
129 * *
130 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000131
Daniel Veillard05d987b2003-10-08 11:54:57 +0000132static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000133 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000134 "Permission denied", /* EACCES */
135 "Resource temporarily unavailable",/* EAGAIN */
136 "Bad file descriptor", /* EBADF */
137 "Bad message", /* EBADMSG */
138 "Resource busy", /* EBUSY */
139 "Operation canceled", /* ECANCELED */
140 "No child processes", /* ECHILD */
141 "Resource deadlock avoided",/* EDEADLK */
142 "Domain error", /* EDOM */
143 "File exists", /* EEXIST */
144 "Bad address", /* EFAULT */
145 "File too large", /* EFBIG */
146 "Operation in progress", /* EINPROGRESS */
147 "Interrupted function call",/* EINTR */
148 "Invalid argument", /* EINVAL */
149 "Input/output error", /* EIO */
150 "Is a directory", /* EISDIR */
151 "Too many open files", /* EMFILE */
152 "Too many links", /* EMLINK */
153 "Inappropriate message buffer length",/* EMSGSIZE */
154 "Filename too long", /* ENAMETOOLONG */
155 "Too many open files in system",/* ENFILE */
156 "No such device", /* ENODEV */
157 "No such file or directory",/* ENOENT */
158 "Exec format error", /* ENOEXEC */
159 "No locks available", /* ENOLCK */
160 "Not enough space", /* ENOMEM */
161 "No space left on device", /* ENOSPC */
162 "Function not implemented", /* ENOSYS */
163 "Not a directory", /* ENOTDIR */
164 "Directory not empty", /* ENOTEMPTY */
165 "Not supported", /* ENOTSUP */
166 "Inappropriate I/O control operation",/* ENOTTY */
167 "No such device or address",/* ENXIO */
168 "Operation not permitted", /* EPERM */
169 "Broken pipe", /* EPIPE */
170 "Result too large", /* ERANGE */
171 "Read-only file system", /* EROFS */
172 "Invalid seek", /* ESPIPE */
173 "No such process", /* ESRCH */
174 "Operation timed out", /* ETIMEDOUT */
175 "Improper link", /* EXDEV */
176 "Attempt to load network entity %s" /* XML_IO_NETWORK_ATTEMPT */
177 "encoder error", /* XML_IO_ENCODER */
178};
179
180/**
181 * xmlIOErrMemory:
182 * @extra: extra informations
183 *
184 * Handle an out of memory condition
185 */
186static void
187xmlIOErrMemory(const char *extra)
188{
189 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
190}
191
192/**
193 * xmlIOErr:
194 * @code: the error number
195 * @extra: extra informations
196 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000197 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000198 */
199static void
200xmlIOErr(int code, const char *extra)
201{
202 unsigned int idx;
203
204 if (code == 0) {
205#ifdef HAVE_ERRNO_H
206 if (errno == 0) code = 0;
207#ifdef EACCES
208 else if (errno == EACCES) code = XML_IO_EACCES;
209#endif
210#ifdef EAGAIN
211 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
212#endif
213#ifdef EBADF
214 else if (errno == EBADF) code = XML_IO_EBADF;
215#endif
216#ifdef EBADMSG
217 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
218#endif
219#ifdef EBUSY
220 else if (errno == EBUSY) code = XML_IO_EBUSY;
221#endif
222#ifdef ECANCELED
223 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
224#endif
225#ifdef ECHILD
226 else if (errno == ECHILD) code = XML_IO_ECHILD;
227#endif
228#ifdef EDEADLK
229 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
230#endif
231#ifdef EDOM
232 else if (errno == EDOM) code = XML_IO_EDOM;
233#endif
234#ifdef EEXIST
235 else if (errno == EEXIST) code = XML_IO_EEXIST;
236#endif
237#ifdef EFAULT
238 else if (errno == EFAULT) code = XML_IO_EFAULT;
239#endif
240#ifdef EFBIG
241 else if (errno == EFBIG) code = XML_IO_EFBIG;
242#endif
243#ifdef EINPROGRESS
244 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
245#endif
246#ifdef EINTR
247 else if (errno == EINTR) code = XML_IO_EINTR;
248#endif
249#ifdef EINVAL
250 else if (errno == EINVAL) code = XML_IO_EINVAL;
251#endif
252#ifdef EIO
253 else if (errno == EIO) code = XML_IO_EIO;
254#endif
255#ifdef EISDIR
256 else if (errno == EISDIR) code = XML_IO_EISDIR;
257#endif
258#ifdef EMFILE
259 else if (errno == EMFILE) code = XML_IO_EMFILE;
260#endif
261#ifdef EMLINK
262 else if (errno == EMLINK) code = XML_IO_EMLINK;
263#endif
264#ifdef EMSGSIZE
265 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
266#endif
267#ifdef ENAMETOOLONG
268 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
269#endif
270#ifdef ENFILE
271 else if (errno == ENFILE) code = XML_IO_ENFILE;
272#endif
273#ifdef ENODEV
274 else if (errno == ENODEV) code = XML_IO_ENODEV;
275#endif
276#ifdef ENOENT
277 else if (errno == ENOENT) code = XML_IO_ENOENT;
278#endif
279#ifdef ENOEXEC
280 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
281#endif
282#ifdef ENOLCK
283 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
284#endif
285#ifdef ENOMEM
286 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
287#endif
288#ifdef ENOSPC
289 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
290#endif
291#ifdef ENOSYS
292 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
293#endif
294#ifdef ENOTDIR
295 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
296#endif
297#ifdef ENOTEMPTY
298 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
299#endif
300#ifdef ENOTSUP
301 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
302#endif
303#ifdef ENOTTY
304 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
305#endif
306#ifdef ENXIO
307 else if (errno == ENXIO) code = XML_IO_ENXIO;
308#endif
309#ifdef EPERM
310 else if (errno == EPERM) code = XML_IO_EPERM;
311#endif
312#ifdef EPIPE
313 else if (errno == EPIPE) code = XML_IO_EPIPE;
314#endif
315#ifdef ERANGE
316 else if (errno == ERANGE) code = XML_IO_ERANGE;
317#endif
318#ifdef EROFS
319 else if (errno == EROFS) code = XML_IO_EROFS;
320#endif
321#ifdef ESPIPE
322 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
323#endif
324#ifdef ESRCH
325 else if (errno == ESRCH) code = XML_IO_ESRCH;
326#endif
327#ifdef ETIMEDOUT
328 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
329#endif
330#ifdef EXDEV
331 else if (errno == EXDEV) code = XML_IO_EXDEV;
332#endif
333 else code = XML_IO_UNKNOWN;
334#endif /* HAVE_ERRNO_H */
335 }
336 idx = 0;
337 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
338 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
339
340 __xmlSimpleError(XML_FROM_IO, code, NULL, IOerr[idx], extra);
341}
342
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000343/**
344 * xmlLoaderErr:
345 * @ctxt: the parser context
346 * @extra: extra informations
347 *
348 * Handle a resource access error
349 */
350static void
351xmlLoaderErr(xmlParserCtxtPtr ctxt, const char *msg, const char *filename)
352{
353 xmlGenericErrorFunc channel = NULL;
354 void *data = NULL;
355 xmlErrorLevel level = XML_ERR_ERROR;
356
357 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
358 if (ctxt->validate) {
359 channel = ctxt->sax->error;
360 level = XML_ERR_ERROR;
361 } else {
362 channel = ctxt->sax->warning;
363 level = XML_ERR_WARNING;
364 }
365 data = ctxt->userData;
366 }
367 __xmlRaiseError(channel, data, ctxt, NULL, XML_FROM_IO,
368 XML_IO_LOAD_ERROR, level, NULL, 0,
369 filename, NULL, NULL, 0, 0,
370 msg, filename);
371
372}
373
Daniel Veillard05d987b2003-10-08 11:54:57 +0000374/************************************************************************
375 * *
376 * Tree memory error handler *
377 * *
378 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000379/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000380 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000381 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000382 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000383 * This function is obsolete. Please see xmlURIFromPath in uri.c for
384 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000385 *
386 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000387 */
388xmlChar *
389xmlNormalizeWindowsPath(const xmlChar *path)
390{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000391 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000392}
393
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000394/**
395 * xmlCleanupInputCallbacks:
396 *
397 * clears the entire input callback table. this includes the
398 * compiled-in I/O.
399 */
400void
401xmlCleanupInputCallbacks(void)
402{
403 int i;
404
405 if (!xmlInputCallbackInitialized)
406 return;
407
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000408 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000409 xmlInputCallbackTable[i].matchcallback = NULL;
410 xmlInputCallbackTable[i].opencallback = NULL;
411 xmlInputCallbackTable[i].readcallback = NULL;
412 xmlInputCallbackTable[i].closecallback = NULL;
413 }
414
415 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000416 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000417}
418
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000419#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000420/**
421 * xmlCleanupOutputCallbacks:
422 *
423 * clears the entire output callback table. this includes the
424 * compiled-in I/O callbacks.
425 */
426void
427xmlCleanupOutputCallbacks(void)
428{
429 int i;
430
431 if (!xmlOutputCallbackInitialized)
432 return;
433
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000434 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000435 xmlOutputCallbackTable[i].matchcallback = NULL;
436 xmlOutputCallbackTable[i].opencallback = NULL;
437 xmlOutputCallbackTable[i].writecallback = NULL;
438 xmlOutputCallbackTable[i].closecallback = NULL;
439 }
440
441 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000442 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000443}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000444#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000445
Owen Taylor3473f882001-02-23 17:55:21 +0000446/************************************************************************
447 * *
448 * Standard I/O for file accesses *
449 * *
450 ************************************************************************/
451
452/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000453 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000454 * @path: the path to check
455 *
456 * function checks to see if @path is a valid source
457 * (file, socket...) for XML.
458 *
459 * if stat is not available on the target machine,
460 * returns 1. if stat fails, returns 0 (if calling
461 * stat on the filename fails, it can't be right).
462 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000463 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000464 */
465
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000466int
Owen Taylor3473f882001-02-23 17:55:21 +0000467xmlCheckFilename (const char *path)
468{
469#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000470 struct stat stat_buffer;
471
472 if (stat(path, &stat_buffer) == -1)
473 return 0;
474
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000475#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000476 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000477 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000478 }
Owen Taylor3473f882001-02-23 17:55:21 +0000479#endif
480#endif
481 return 1;
482}
483
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000484static int
Owen Taylor3473f882001-02-23 17:55:21 +0000485xmlNop(void) {
486 return(0);
487}
488
489/**
Owen Taylor3473f882001-02-23 17:55:21 +0000490 * xmlFdRead:
491 * @context: the I/O context
492 * @buffer: where to drop data
493 * @len: number of bytes to read
494 *
495 * Read @len bytes to @buffer from the I/O channel.
496 *
497 * Returns the number of bytes written
498 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000499static int
Owen Taylor3473f882001-02-23 17:55:21 +0000500xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000501 int ret;
502
503 ret = read((int) (long) context, &buffer[0], len);
504 if (ret < 0) xmlIOErr(0, "read()");
505 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000506}
507
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000508#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000509/**
510 * xmlFdWrite:
511 * @context: the I/O context
512 * @buffer: where to get data
513 * @len: number of bytes to write
514 *
515 * Write @len bytes from @buffer to the I/O channel.
516 *
517 * Returns the number of bytes written
518 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000519static int
Owen Taylor3473f882001-02-23 17:55:21 +0000520xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000521 int ret;
522
523 ret = write((int) (long) context, &buffer[0], len);
524 if (ret < 0) xmlIOErr(0, "write()");
525 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000526}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000527#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000528
529/**
530 * xmlFdClose:
531 * @context: the I/O context
532 *
533 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000534 *
535 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000536 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000537static int
Owen Taylor3473f882001-02-23 17:55:21 +0000538xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000539 int ret;
540 ret = close((int) (long) context);
541 if (ret < 0) xmlIOErr(0, "close()");
542 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000543}
544
545/**
546 * xmlFileMatch:
547 * @filename: the URI for matching
548 *
549 * input from FILE *
550 *
551 * Returns 1 if matches, 0 otherwise
552 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000553int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000554xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000555 return(1);
556}
557
558/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000559 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000560 * @filename: the URI for matching
561 *
562 * input from FILE *, supports compressed input
563 * if @filename is " " then the standard input is used
564 *
565 * Returns an I/O context or NULL in case of error
566 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000567static void *
568xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000569 const char *path = NULL;
570 FILE *fd;
571
572 if (!strcmp(filename, "-")) {
573 fd = stdin;
574 return((void *) fd);
575 }
576
Daniel Veillardf4862f02002-09-10 11:13:43 +0000577 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000578#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000579 path = &filename[17];
580#else
Owen Taylor3473f882001-02-23 17:55:21 +0000581 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000582#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000583 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000584#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000585 path = &filename[8];
586#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000587 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000588#endif
589 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000590 path = filename;
591
592 if (path == NULL)
593 return(NULL);
594 if (!xmlCheckFilename(path))
595 return(NULL);
596
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000597#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000598 fd = fopen(path, "rb");
599#else
600 fd = fopen(path, "r");
601#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000602 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000603 return((void *) fd);
604}
605
606/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000607 * xmlFileOpen:
608 * @filename: the URI for matching
609 *
610 * Wrapper around xmlFileOpen_real that try it with an unescaped
611 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000612 *
613 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000614 */
615void *
616xmlFileOpen (const char *filename) {
617 char *unescaped;
618 void *retval;
619 unescaped = xmlURIUnescapeString(filename, 0, NULL);
620 if (unescaped != NULL) {
621 retval = xmlFileOpen_real(unescaped);
622 } else {
623 retval = xmlFileOpen_real(filename);
624 }
625 xmlFree(unescaped);
626 return retval;
627}
628
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000629#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000630/**
Owen Taylor3473f882001-02-23 17:55:21 +0000631 * xmlFileOpenW:
632 * @filename: the URI for matching
633 *
634 * output to from FILE *,
635 * if @filename is "-" then the standard output is used
636 *
637 * Returns an I/O context or NULL in case of error
638 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000639static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000640xmlFileOpenW (const char *filename) {
641 const char *path = NULL;
642 FILE *fd;
643
644 if (!strcmp(filename, "-")) {
645 fd = stdout;
646 return((void *) fd);
647 }
648
Daniel Veillardf4862f02002-09-10 11:13:43 +0000649 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000650#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000651 path = &filename[17];
652#else
Owen Taylor3473f882001-02-23 17:55:21 +0000653 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000654#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000655 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000656#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000657 path = &filename[8];
658#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000659 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000660#endif
661 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000662 path = filename;
663
664 if (path == NULL)
665 return(NULL);
666
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000667 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000668 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000669 return((void *) fd);
670}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000671#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000672
673/**
674 * xmlFileRead:
675 * @context: the I/O context
676 * @buffer: where to drop data
677 * @len: number of bytes to write
678 *
679 * Read @len bytes to @buffer from the I/O channel.
680 *
681 * Returns the number of bytes written
682 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000683int
Owen Taylor3473f882001-02-23 17:55:21 +0000684xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000685 int ret;
686 ret = fread(&buffer[0], 1, len, (FILE *) context);
687 if (ret < 0) xmlIOErr(0, "fread()");
688 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000689}
690
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000691#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000692/**
693 * xmlFileWrite:
694 * @context: the I/O context
695 * @buffer: where to drop data
696 * @len: number of bytes to write
697 *
698 * Write @len bytes from @buffer to the I/O channel.
699 *
700 * Returns the number of bytes written
701 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000702static int
Owen Taylor3473f882001-02-23 17:55:21 +0000703xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000704 int items;
705
706 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000707 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000708 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000709 return(-1);
710 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000711 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000712}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000713#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000714
715/**
716 * xmlFileClose:
717 * @context: the I/O context
718 *
719 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000720 *
721 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000722 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000723int
Owen Taylor3473f882001-02-23 17:55:21 +0000724xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000725 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000726 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000727
728 fil = (FILE *) context;
729 if (fil == stdin)
730 return(0);
731 if (fil == stdout)
732 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000733 if (fil == stderr)
734 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000735 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
736 if (ret < 0)
737 xmlIOErr(0, "fclose()");
738 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000739}
740
741/**
742 * xmlFileFlush:
743 * @context: the I/O context
744 *
745 * Flush an I/O channel
746 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000747static int
Owen Taylor3473f882001-02-23 17:55:21 +0000748xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000749 int ret;
750 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
751 if (ret < 0)
752 xmlIOErr(0, "fflush()");
753 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000754}
755
756#ifdef HAVE_ZLIB_H
757/************************************************************************
758 * *
759 * I/O for compressed file accesses *
760 * *
761 ************************************************************************/
762/**
763 * xmlGzfileMatch:
764 * @filename: the URI for matching
765 *
766 * input from compressed file test
767 *
768 * Returns 1 if matches, 0 otherwise
769 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000770static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000771xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000772 return(1);
773}
774
775/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000776 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000777 * @filename: the URI for matching
778 *
779 * input from compressed file open
780 * if @filename is " " then the standard input is used
781 *
782 * Returns an I/O context or NULL in case of error
783 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000784static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000785xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000786 const char *path = NULL;
787 gzFile fd;
788
789 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000790 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000791 return((void *) fd);
792 }
793
Daniel Veillardf4862f02002-09-10 11:13:43 +0000794 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000795#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000796 path = &filename[17];
797#else
Owen Taylor3473f882001-02-23 17:55:21 +0000798 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000799#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000800 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000801#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000802 path = &filename[8];
803#else
Owen Taylor3473f882001-02-23 17:55:21 +0000804 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000805#endif
806 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000807 path = filename;
808
809 if (path == NULL)
810 return(NULL);
811 if (!xmlCheckFilename(path))
812 return(NULL);
813
814 fd = gzopen(path, "rb");
815 return((void *) fd);
816}
817
818/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000819 * xmlGzfileOpen:
820 * @filename: the URI for matching
821 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000822 * Wrapper around xmlGzfileOpen if the open fais, it will
823 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000824 */
825static void *
826xmlGzfileOpen (const char *filename) {
827 char *unescaped;
828 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000829
830 retval = xmlGzfileOpen_real(filename);
831 if (retval == NULL) {
832 unescaped = xmlURIUnescapeString(filename, 0, NULL);
833 if (unescaped != NULL) {
834 retval = xmlGzfileOpen_real(unescaped);
835 }
836 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000837 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000838 return retval;
839}
840
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000841#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000842/**
Owen Taylor3473f882001-02-23 17:55:21 +0000843 * xmlGzfileOpenW:
844 * @filename: the URI for matching
845 * @compression: the compression factor (0 - 9 included)
846 *
847 * input from compressed file open
848 * if @filename is " " then the standard input is used
849 *
850 * Returns an I/O context or NULL in case of error
851 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000852static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000853xmlGzfileOpenW (const char *filename, int compression) {
854 const char *path = NULL;
855 char mode[15];
856 gzFile fd;
857
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000858 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000859 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000860 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000861 return((void *) fd);
862 }
863
Daniel Veillardf4862f02002-09-10 11:13:43 +0000864 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000865#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000866 path = &filename[17];
867#else
Owen Taylor3473f882001-02-23 17:55:21 +0000868 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000869#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000870 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000871#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000872 path = &filename[8];
873#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000874 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000875#endif
876 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000877 path = filename;
878
879 if (path == NULL)
880 return(NULL);
881
882 fd = gzopen(path, mode);
883 return((void *) fd);
884}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000885#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000886
887/**
888 * xmlGzfileRead:
889 * @context: the I/O context
890 * @buffer: where to drop data
891 * @len: number of bytes to write
892 *
893 * Read @len bytes to @buffer from the compressed I/O channel.
894 *
895 * Returns the number of bytes written
896 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000897static int
Owen Taylor3473f882001-02-23 17:55:21 +0000898xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000899 int ret;
900
901 ret = gzread((gzFile) context, &buffer[0], len);
902 if (ret < 0) xmlIOErr(0, "gzread()");
903 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000904}
905
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000906#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000907/**
908 * xmlGzfileWrite:
909 * @context: the I/O context
910 * @buffer: where to drop data
911 * @len: number of bytes to write
912 *
913 * Write @len bytes from @buffer to the compressed I/O channel.
914 *
915 * Returns the number of bytes written
916 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000917static int
Owen Taylor3473f882001-02-23 17:55:21 +0000918xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000919 int ret;
920
921 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
922 if (ret < 0) xmlIOErr(0, "gzwrite()");
923 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000924}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000925#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000926
927/**
928 * xmlGzfileClose:
929 * @context: the I/O context
930 *
931 * Close a compressed I/O channel
932 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000933static int
Owen Taylor3473f882001-02-23 17:55:21 +0000934xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000935 int ret;
936
937 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
938 if (ret < 0) xmlIOErr(0, "gzclose()");
939 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000940}
941#endif /* HAVE_ZLIB_H */
942
943#ifdef LIBXML_HTTP_ENABLED
944/************************************************************************
945 * *
946 * I/O for HTTP file accesses *
947 * *
948 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000949
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000950#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +0000951typedef struct xmlIOHTTPWriteCtxt_
952{
953 int compression;
954
955 char * uri;
956
957 void * doc_buff;
958
959} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
960
961#ifdef HAVE_ZLIB_H
962
963#define DFLT_WBITS ( -15 )
964#define DFLT_MEM_LVL ( 8 )
965#define GZ_MAGIC1 ( 0x1f )
966#define GZ_MAGIC2 ( 0x8b )
967#define LXML_ZLIB_OS_CODE ( 0x03 )
968#define INIT_HTTP_BUFF_SIZE ( 32768 )
969#define DFLT_ZLIB_RATIO ( 5 )
970
971/*
972** Data structure and functions to work with sending compressed data
973** via HTTP.
974*/
975
976typedef struct xmlZMemBuff_
977{
978 unsigned long size;
979 unsigned long crc;
980
981 unsigned char * zbuff;
982 z_stream zctrl;
983
984} xmlZMemBuff, *xmlZMemBuffPtr;
985
986/**
987 * append_reverse_ulong
988 * @buff: Compressed memory buffer
989 * @data: Unsigned long to append
990 *
991 * Append a unsigned long in reverse byte order to the end of the
992 * memory buffer.
993 */
994static void
995append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
996
997 int idx;
998
999 if ( buff == NULL )
1000 return;
1001
1002 /*
1003 ** This is plagiarized from putLong in gzio.c (zlib source) where
1004 ** the number "4" is hardcoded. If zlib is ever patched to
1005 ** support 64 bit file sizes, this code would need to be patched
1006 ** as well.
1007 */
1008
1009 for ( idx = 0; idx < 4; idx++ ) {
1010 *buff->zctrl.next_out = ( data & 0xff );
1011 data >>= 8;
1012 buff->zctrl.next_out++;
1013 }
1014
1015 return;
1016}
1017
1018/**
1019 *
1020 * xmlFreeZMemBuff
1021 * @buff: The memory buffer context to clear
1022 *
1023 * Release all the resources associated with the compressed memory buffer.
1024 */
1025static void
1026xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001027
1028#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001029 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001030#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001031
1032 if ( buff == NULL )
1033 return;
1034
1035 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001036#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001037 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001038 if ( z_err != Z_OK )
1039 xmlGenericError( xmlGenericErrorContext,
1040 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1041 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001042#else
1043 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001044#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001045
1046 xmlFree( buff );
1047 return;
1048}
1049
1050/**
1051 * xmlCreateZMemBuff
1052 *@compression: Compression value to use
1053 *
1054 * Create a memory buffer to hold the compressed XML document. The
1055 * compressed document in memory will end up being identical to what
1056 * would be created if gzopen/gzwrite/gzclose were being used to
1057 * write the document to disk. The code for the header/trailer data to
1058 * the compression is plagiarized from the zlib source files.
1059 */
1060static void *
1061xmlCreateZMemBuff( int compression ) {
1062
1063 int z_err;
1064 int hdr_lgth;
1065 xmlZMemBuffPtr buff = NULL;
1066
1067 if ( ( compression < 1 ) || ( compression > 9 ) )
1068 return ( NULL );
1069
1070 /* Create the control and data areas */
1071
1072 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1073 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001074 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001075 return ( NULL );
1076 }
1077
1078 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1079 buff->size = INIT_HTTP_BUFF_SIZE;
1080 buff->zbuff = xmlMalloc( buff->size );
1081 if ( buff->zbuff == NULL ) {
1082 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001083 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001084 return ( NULL );
1085 }
1086
1087 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1088 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1089 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001090 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001091 xmlFreeZMemBuff( buff );
1092 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001093 xmlStrPrintf(msg, 500,
1094 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1095 "Error initializing compression context. ZLIB error:",
1096 z_err );
1097 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001098 return ( NULL );
1099 }
1100
1101 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001102 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001103 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1104 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001105 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1106 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1107 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1108 buff->zctrl.avail_out = buff->size - hdr_lgth;
1109
1110 return ( buff );
1111}
1112
1113/**
1114 * xmlZMemBuffExtend
1115 * @buff: Buffer used to compress and consolidate data.
1116 * @ext_amt: Number of bytes to extend the buffer.
1117 *
1118 * Extend the internal buffer used to store the compressed data by the
1119 * specified amount.
1120 *
1121 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1122 * the original buffer still exists at the original size.
1123 */
1124static int
1125xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1126
1127 int rc = -1;
1128 size_t new_size;
1129 size_t cur_used;
1130
1131 unsigned char * tmp_ptr = NULL;
1132
1133 if ( buff == NULL )
1134 return ( -1 );
1135
1136 else if ( ext_amt == 0 )
1137 return ( 0 );
1138
1139 cur_used = buff->zctrl.next_out - buff->zbuff;
1140 new_size = buff->size + ext_amt;
1141
1142#ifdef DEBUG_HTTP
1143 if ( cur_used > new_size )
1144 xmlGenericError( xmlGenericErrorContext,
1145 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1146 "Buffer overwrite detected during compressed memory",
1147 "buffer extension. Overflowed by",
1148 (cur_used - new_size ) );
1149#endif
1150
1151 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1152 if ( tmp_ptr != NULL ) {
1153 rc = 0;
1154 buff->size = new_size;
1155 buff->zbuff = tmp_ptr;
1156 buff->zctrl.next_out = tmp_ptr + cur_used;
1157 buff->zctrl.avail_out = new_size - cur_used;
1158 }
1159 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001160 xmlChar msg[500];
1161 xmlStrPrintf(msg, 500,
1162 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1163 "Allocation failure extending output buffer to",
1164 new_size );
1165 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001166 }
1167
1168 return ( rc );
1169}
1170
1171/**
1172 * xmlZMemBuffAppend
1173 * @buff: Buffer used to compress and consolidate data
1174 * @src: Uncompressed source content to append to buffer
1175 * @len: Length of source data to append to buffer
1176 *
1177 * Compress and append data to the internal buffer. The data buffer
1178 * will be expanded if needed to store the additional data.
1179 *
1180 * Returns the number of bytes appended to the buffer or -1 on error.
1181 */
1182static int
1183xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1184
1185 int z_err;
1186 size_t min_accept;
1187
1188 if ( ( buff == NULL ) || ( src == NULL ) )
1189 return ( -1 );
1190
1191 buff->zctrl.avail_in = len;
1192 buff->zctrl.next_in = (unsigned char *)src;
1193 while ( buff->zctrl.avail_in > 0 ) {
1194 /*
1195 ** Extend the buffer prior to deflate call if a reasonable amount
1196 ** of output buffer space is not available.
1197 */
1198 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1199 if ( buff->zctrl.avail_out <= min_accept ) {
1200 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1201 return ( -1 );
1202 }
1203
1204 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1205 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001206 xmlChar msg[500];
1207 xmlStrPrintf(msg, 500,
1208 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001209 "Compression error while appending",
1210 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001211 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001212 return ( -1 );
1213 }
1214 }
1215
1216 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1217
1218 return ( len );
1219}
1220
1221/**
1222 * xmlZMemBuffGetContent
1223 * @buff: Compressed memory content buffer
1224 * @data_ref: Pointer reference to point to compressed content
1225 *
1226 * Flushes the compression buffers, appends gzip file trailers and
1227 * returns the compressed content and length of the compressed data.
1228 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1229 *
1230 * Returns the length of the compressed data or -1 on error.
1231 */
1232static int
1233xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1234
1235 int zlgth = -1;
1236 int z_err;
1237
1238 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1239 return ( -1 );
1240
1241 /* Need to loop until compression output buffers are flushed */
1242
1243 do
1244 {
1245 z_err = deflate( &buff->zctrl, Z_FINISH );
1246 if ( z_err == Z_OK ) {
1247 /* In this case Z_OK means more buffer space needed */
1248
1249 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1250 return ( -1 );
1251 }
1252 }
1253 while ( z_err == Z_OK );
1254
1255 /* If the compression state is not Z_STREAM_END, some error occurred */
1256
1257 if ( z_err == Z_STREAM_END ) {
1258
1259 /* Need to append the gzip data trailer */
1260
1261 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1262 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1263 return ( -1 );
1264 }
1265
1266 /*
1267 ** For whatever reason, the CRC and length data are pushed out
1268 ** in reverse byte order. So a memcpy can't be used here.
1269 */
1270
1271 append_reverse_ulong( buff, buff->crc );
1272 append_reverse_ulong( buff, buff->zctrl.total_in );
1273
1274 zlgth = buff->zctrl.next_out - buff->zbuff;
1275 *data_ref = (char *)buff->zbuff;
1276 }
1277
Daniel Veillard05d987b2003-10-08 11:54:57 +00001278 else {
1279 xmlChar msg[500];
1280 xmlStrPrintf(msg, 500,
1281 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1282 "Error flushing zlib buffers. Error code", z_err );
1283 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1284 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001285
1286 return ( zlgth );
1287}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001288#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001289#endif /* HAVE_ZLIB_H */
1290
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001291#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001292/**
1293 * xmlFreeHTTPWriteCtxt
1294 * @ctxt: Context to cleanup
1295 *
1296 * Free allocated memory and reclaim system resources.
1297 *
1298 * No return value.
1299 */
1300static void
1301xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1302{
1303 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001304 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001305
1306 if ( ctxt->doc_buff != NULL ) {
1307
1308#ifdef HAVE_ZLIB_H
1309 if ( ctxt->compression > 0 ) {
1310 xmlFreeZMemBuff( ctxt->doc_buff );
1311 }
1312 else
1313#endif
1314 {
1315 xmlOutputBufferClose( ctxt->doc_buff );
1316 }
1317 }
1318
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001319 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001320 return;
1321}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001322#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001323
1324
Owen Taylor3473f882001-02-23 17:55:21 +00001325/**
1326 * xmlIOHTTPMatch:
1327 * @filename: the URI for matching
1328 *
1329 * check if the URI matches an HTTP one
1330 *
1331 * Returns 1 if matches, 0 otherwise
1332 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001333int
Owen Taylor3473f882001-02-23 17:55:21 +00001334xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001335 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001336 return(1);
1337 return(0);
1338}
1339
1340/**
1341 * xmlIOHTTPOpen:
1342 * @filename: the URI for matching
1343 *
1344 * open an HTTP I/O channel
1345 *
1346 * Returns an I/O context or NULL in case of error
1347 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001348void *
Owen Taylor3473f882001-02-23 17:55:21 +00001349xmlIOHTTPOpen (const char *filename) {
1350 return(xmlNanoHTTPOpen(filename, NULL));
1351}
1352
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001353#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001354/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001355 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001356 * @post_uri: The destination URI for the document
1357 * @compression: The compression desired for the document.
1358 *
1359 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1360 * request. Non-static as is called from the output buffer creation routine.
1361 *
1362 * Returns an I/O context or NULL in case of error.
1363 */
1364
1365void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001366xmlIOHTTPOpenW(const char *post_uri, int compression)
1367{
Daniel Veillardf012a642001-07-23 19:10:52 +00001368
Daniel Veillard572577e2002-01-18 16:23:55 +00001369 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001370
Daniel Veillard572577e2002-01-18 16:23:55 +00001371 if (post_uri == NULL)
1372 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001373
Daniel Veillard572577e2002-01-18 16:23:55 +00001374 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1375 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001376 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001377 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001378 }
1379
Daniel Veillard572577e2002-01-18 16:23:55 +00001380 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001381
Daniel Veillard572577e2002-01-18 16:23:55 +00001382 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1383 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001384 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001385 xmlFreeHTTPWriteCtxt(ctxt);
1386 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001387 }
1388
1389 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001390 * ** Since the document length is required for an HTTP post,
1391 * ** need to put the document into a buffer. A memory buffer
1392 * ** is being used to avoid pushing the data to disk and back.
1393 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001394
1395#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001396 if ((compression > 0) && (compression <= 9)) {
1397
1398 ctxt->compression = compression;
1399 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1400 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001401#endif
1402 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001403 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001404
Daniel Veillard572577e2002-01-18 16:23:55 +00001405 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001406 }
1407
Daniel Veillard572577e2002-01-18 16:23:55 +00001408 if (ctxt->doc_buff == NULL) {
1409 xmlFreeHTTPWriteCtxt(ctxt);
1410 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001411 }
1412
Daniel Veillard572577e2002-01-18 16:23:55 +00001413 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001414}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001415#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001416
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001417#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001418/**
1419 * xmlIOHTTPDfltOpenW
1420 * @post_uri: The destination URI for this document.
1421 *
1422 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1423 * HTTP post command. This function should generally not be used as
1424 * the open callback is short circuited in xmlOutputBufferCreateFile.
1425 *
1426 * Returns a pointer to the new IO context.
1427 */
1428static void *
1429xmlIOHTTPDfltOpenW( const char * post_uri ) {
1430 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1431}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001432#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001433
1434/**
Owen Taylor3473f882001-02-23 17:55:21 +00001435 * xmlIOHTTPRead:
1436 * @context: the I/O context
1437 * @buffer: where to drop data
1438 * @len: number of bytes to write
1439 *
1440 * Read @len bytes to @buffer from the I/O channel.
1441 *
1442 * Returns the number of bytes written
1443 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001444int
Owen Taylor3473f882001-02-23 17:55:21 +00001445xmlIOHTTPRead(void * context, char * buffer, int len) {
1446 return(xmlNanoHTTPRead(context, &buffer[0], len));
1447}
1448
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001449#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001450/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001451 * xmlIOHTTPWrite
1452 * @context: previously opened writing context
1453 * @buffer: data to output to temporary buffer
1454 * @len: bytes to output
1455 *
1456 * Collect data from memory buffer into a temporary file for later
1457 * processing.
1458 *
1459 * Returns number of bytes written.
1460 */
1461
1462static int
1463xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1464
1465 xmlIOHTTPWriteCtxtPtr ctxt = context;
1466
1467 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1468 return ( -1 );
1469
1470 if ( len > 0 ) {
1471
1472 /* Use gzwrite or fwrite as previously setup in the open call */
1473
1474#ifdef HAVE_ZLIB_H
1475 if ( ctxt->compression > 0 )
1476 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1477
1478 else
1479#endif
1480 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1481
1482 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001483 xmlChar msg[500];
1484 xmlStrPrintf(msg, 500,
1485 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001486 "Error appending to internal buffer.",
1487 "Error sending document to URI",
1488 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001489 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001490 }
1491 }
1492
1493 return ( len );
1494}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001495#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001496
1497
1498/**
Owen Taylor3473f882001-02-23 17:55:21 +00001499 * xmlIOHTTPClose:
1500 * @context: the I/O context
1501 *
1502 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001503 *
1504 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001505 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001506int
Owen Taylor3473f882001-02-23 17:55:21 +00001507xmlIOHTTPClose (void * context) {
1508 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001509 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001510}
Daniel Veillardf012a642001-07-23 19:10:52 +00001511
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001512#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001513/**
1514 * xmlIOHTTCloseWrite
1515 * @context: The I/O context
1516 * @http_mthd: The HTTP method to be used when sending the data
1517 *
1518 * Close the transmit HTTP I/O channel and actually send the data.
1519 */
1520static int
1521xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1522
1523 int close_rc = -1;
1524 int http_rtn = 0;
1525 int content_lgth = 0;
1526 xmlIOHTTPWriteCtxtPtr ctxt = context;
1527
1528 char * http_content = NULL;
1529 char * content_encoding = NULL;
1530 char * content_type = (char *) "text/xml";
1531 void * http_ctxt = NULL;
1532
1533 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1534 return ( -1 );
1535
1536 /* Retrieve the content from the appropriate buffer */
1537
1538#ifdef HAVE_ZLIB_H
1539
1540 if ( ctxt->compression > 0 ) {
1541 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1542 content_encoding = (char *) "Content-Encoding: gzip";
1543 }
1544 else
1545#endif
1546 {
1547 /* Pull the data out of the memory output buffer */
1548
1549 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1550 http_content = (char *)dctxt->buffer->content;
1551 content_lgth = dctxt->buffer->use;
1552 }
1553
1554 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001555 xmlChar msg[500];
1556 xmlStrPrintf(msg, 500,
1557 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1558 "Error retrieving content.\nUnable to",
1559 http_mthd, "data to URI", ctxt->uri );
1560 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001561 }
1562
1563 else {
1564
1565 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1566 &content_type, content_encoding,
1567 content_lgth );
1568
1569 if ( http_ctxt != NULL ) {
1570#ifdef DEBUG_HTTP
1571 /* If testing/debugging - dump reply with request content */
1572
1573 FILE * tst_file = NULL;
1574 char buffer[ 4096 ];
1575 char * dump_name = NULL;
1576 int avail;
1577
1578 xmlGenericError( xmlGenericErrorContext,
1579 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1580 http_mthd, ctxt->uri,
1581 xmlNanoHTTPReturnCode( http_ctxt ) );
1582
1583 /*
1584 ** Since either content or reply may be gzipped,
1585 ** dump them to separate files instead of the
1586 ** standard error context.
1587 */
1588
1589 dump_name = tempnam( NULL, "lxml" );
1590 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001591 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001592
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001593 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001594 if ( tst_file != NULL ) {
1595 xmlGenericError( xmlGenericErrorContext,
1596 "Transmitted content saved in file: %s\n", buffer );
1597
1598 fwrite( http_content, sizeof( char ),
1599 content_lgth, tst_file );
1600 fclose( tst_file );
1601 }
1602
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001603 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001604 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001605 if ( tst_file != NULL ) {
1606 xmlGenericError( xmlGenericErrorContext,
1607 "Reply content saved in file: %s\n", buffer );
1608
1609
1610 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1611 buffer, sizeof( buffer ) )) > 0 ) {
1612
1613 fwrite( buffer, sizeof( char ), avail, tst_file );
1614 }
1615
1616 fclose( tst_file );
1617 }
1618
1619 free( dump_name );
1620 }
1621#endif /* DEBUG_HTTP */
1622
1623 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1624 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1625 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001626 else {
1627 xmlChar msg[500];
1628 xmlStrPrintf(msg, 500,
1629 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001630 http_mthd, content_lgth,
1631 "bytes to URI", ctxt->uri,
1632 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001633 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1634 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001635
1636 xmlNanoHTTPClose( http_ctxt );
1637 xmlFree( content_type );
1638 }
1639 }
1640
1641 /* Final cleanups */
1642
1643 xmlFreeHTTPWriteCtxt( ctxt );
1644
1645 return ( close_rc );
1646}
1647
1648/**
1649 * xmlIOHTTPClosePut
1650 *
1651 * @context: The I/O context
1652 *
1653 * Close the transmit HTTP I/O channel and actually send data using a PUT
1654 * HTTP method.
1655 */
1656static int
1657xmlIOHTTPClosePut( void * ctxt ) {
1658 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1659}
1660
1661
1662/**
1663 * xmlIOHTTPClosePost
1664 *
1665 * @context: The I/O context
1666 *
1667 * Close the transmit HTTP I/O channel and actually send data using a POST
1668 * HTTP method.
1669 */
1670static int
1671xmlIOHTTPClosePost( void * ctxt ) {
1672 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1673}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001674#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001675
Owen Taylor3473f882001-02-23 17:55:21 +00001676#endif /* LIBXML_HTTP_ENABLED */
1677
1678#ifdef LIBXML_FTP_ENABLED
1679/************************************************************************
1680 * *
1681 * I/O for FTP file accesses *
1682 * *
1683 ************************************************************************/
1684/**
1685 * xmlIOFTPMatch:
1686 * @filename: the URI for matching
1687 *
1688 * check if the URI matches an FTP one
1689 *
1690 * Returns 1 if matches, 0 otherwise
1691 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001692int
Owen Taylor3473f882001-02-23 17:55:21 +00001693xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001694 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001695 return(1);
1696 return(0);
1697}
1698
1699/**
1700 * xmlIOFTPOpen:
1701 * @filename: the URI for matching
1702 *
1703 * open an FTP I/O channel
1704 *
1705 * Returns an I/O context or NULL in case of error
1706 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001707void *
Owen Taylor3473f882001-02-23 17:55:21 +00001708xmlIOFTPOpen (const char *filename) {
1709 return(xmlNanoFTPOpen(filename));
1710}
1711
1712/**
1713 * xmlIOFTPRead:
1714 * @context: the I/O context
1715 * @buffer: where to drop data
1716 * @len: number of bytes to write
1717 *
1718 * Read @len bytes to @buffer from the I/O channel.
1719 *
1720 * Returns the number of bytes written
1721 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001722int
Owen Taylor3473f882001-02-23 17:55:21 +00001723xmlIOFTPRead(void * context, char * buffer, int len) {
1724 return(xmlNanoFTPRead(context, &buffer[0], len));
1725}
1726
1727/**
1728 * xmlIOFTPClose:
1729 * @context: the I/O context
1730 *
1731 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001732 *
1733 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001734 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001735int
Owen Taylor3473f882001-02-23 17:55:21 +00001736xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001737 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001738}
1739#endif /* LIBXML_FTP_ENABLED */
1740
1741
1742/**
1743 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001744 * @matchFunc: the xmlInputMatchCallback
1745 * @openFunc: the xmlInputOpenCallback
1746 * @readFunc: the xmlInputReadCallback
1747 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001748 *
1749 * Register a new set of I/O callback for handling parser input.
1750 *
1751 * Returns the registered handler number or -1 in case of error
1752 */
1753int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001754xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1755 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1756 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001757 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1758 return(-1);
1759 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001760 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1761 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1762 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1763 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001764 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001765 return(xmlInputCallbackNr++);
1766}
1767
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001768#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001769/**
1770 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001771 * @matchFunc: the xmlOutputMatchCallback
1772 * @openFunc: the xmlOutputOpenCallback
1773 * @writeFunc: the xmlOutputWriteCallback
1774 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001775 *
1776 * Register a new set of I/O callback for handling output.
1777 *
1778 * Returns the registered handler number or -1 in case of error
1779 */
1780int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001781xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1782 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1783 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001784 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1785 return(-1);
1786 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001787 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1788 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1789 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1790 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001791 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001792 return(xmlOutputCallbackNr++);
1793}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001794#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001795
1796/**
1797 * xmlRegisterDefaultInputCallbacks:
1798 *
1799 * Registers the default compiled-in I/O handlers.
1800 */
1801void
Owen Taylor3473f882001-02-23 17:55:21 +00001802xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001803(void) {
1804 if (xmlInputCallbackInitialized)
1805 return;
1806
1807 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1808 xmlFileRead, xmlFileClose);
1809#ifdef HAVE_ZLIB_H
1810 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1811 xmlGzfileRead, xmlGzfileClose);
1812#endif /* HAVE_ZLIB_H */
1813
1814#ifdef LIBXML_HTTP_ENABLED
1815 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1816 xmlIOHTTPRead, xmlIOHTTPClose);
1817#endif /* LIBXML_HTTP_ENABLED */
1818
1819#ifdef LIBXML_FTP_ENABLED
1820 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1821 xmlIOFTPRead, xmlIOFTPClose);
1822#endif /* LIBXML_FTP_ENABLED */
1823 xmlInputCallbackInitialized = 1;
1824}
1825
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001826#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001827/**
1828 * xmlRegisterDefaultOutputCallbacks:
1829 *
1830 * Registers the default compiled-in I/O handlers.
1831 */
1832void
Owen Taylor3473f882001-02-23 17:55:21 +00001833xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001834(void) {
1835 if (xmlOutputCallbackInitialized)
1836 return;
1837
1838 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1839 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001840
1841#ifdef LIBXML_HTTP_ENABLED
1842 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1843 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1844#endif
1845
Owen Taylor3473f882001-02-23 17:55:21 +00001846/*********************************
1847 No way a-priori to distinguish between gzipped files from
1848 uncompressed ones except opening if existing then closing
1849 and saving with same compression ratio ... a pain.
1850
1851#ifdef HAVE_ZLIB_H
1852 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1853 xmlGzfileWrite, xmlGzfileClose);
1854#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001855
1856 Nor FTP PUT ....
1857#ifdef LIBXML_FTP_ENABLED
1858 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1859 xmlIOFTPWrite, xmlIOFTPClose);
1860#endif
1861 **********************************/
1862 xmlOutputCallbackInitialized = 1;
1863}
1864
Daniel Veillardf012a642001-07-23 19:10:52 +00001865#ifdef LIBXML_HTTP_ENABLED
1866/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001867 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001868 *
1869 * By default, libxml submits HTTP output requests using the "PUT" method.
1870 * Calling this method changes the HTTP output method to use the "POST"
1871 * method instead.
1872 *
1873 */
1874void
1875xmlRegisterHTTPPostCallbacks( void ) {
1876
1877 /* Register defaults if not done previously */
1878
1879 if ( xmlOutputCallbackInitialized == 0 )
1880 xmlRegisterDefaultOutputCallbacks( );
1881
1882 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1883 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1884 return;
1885}
1886#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001887#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001888
Owen Taylor3473f882001-02-23 17:55:21 +00001889/**
1890 * xmlAllocParserInputBuffer:
1891 * @enc: the charset encoding if known
1892 *
1893 * Create a buffered parser input for progressive parsing
1894 *
1895 * Returns the new parser input or NULL
1896 */
1897xmlParserInputBufferPtr
1898xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1899 xmlParserInputBufferPtr ret;
1900
1901 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1902 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001903 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001904 return(NULL);
1905 }
1906 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001907 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001908 if (ret->buffer == NULL) {
1909 xmlFree(ret);
1910 return(NULL);
1911 }
1912 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1913 ret->encoder = xmlGetCharEncodingHandler(enc);
1914 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001915 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001916 else
1917 ret->raw = NULL;
1918 ret->readcallback = NULL;
1919 ret->closecallback = NULL;
1920 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00001921 ret->compressed = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00001922
1923 return(ret);
1924}
1925
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001926#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001927/**
1928 * xmlAllocOutputBuffer:
1929 * @encoder: the encoding converter or NULL
1930 *
1931 * Create a buffered parser output
1932 *
1933 * Returns the new parser output or NULL
1934 */
1935xmlOutputBufferPtr
1936xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1937 xmlOutputBufferPtr ret;
1938
1939 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1940 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001941 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001942 return(NULL);
1943 }
1944 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1945 ret->buffer = xmlBufferCreate();
1946 if (ret->buffer == NULL) {
1947 xmlFree(ret);
1948 return(NULL);
1949 }
1950 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1951 ret->encoder = encoder;
1952 if (encoder != NULL) {
1953 ret->conv = xmlBufferCreateSize(4000);
1954 /*
1955 * This call is designed to initiate the encoder state
1956 */
1957 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1958 } else
1959 ret->conv = NULL;
1960 ret->writecallback = NULL;
1961 ret->closecallback = NULL;
1962 ret->context = NULL;
1963 ret->written = 0;
1964
1965 return(ret);
1966}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001967#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001968
1969/**
1970 * xmlFreeParserInputBuffer:
1971 * @in: a buffered parser input
1972 *
1973 * Free up the memory used by a buffered parser input
1974 */
1975void
1976xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00001977 if (in == NULL) return;
1978
Owen Taylor3473f882001-02-23 17:55:21 +00001979 if (in->raw) {
1980 xmlBufferFree(in->raw);
1981 in->raw = NULL;
1982 }
1983 if (in->encoder != NULL) {
1984 xmlCharEncCloseFunc(in->encoder);
1985 }
1986 if (in->closecallback != NULL) {
1987 in->closecallback(in->context);
1988 }
1989 if (in->buffer != NULL) {
1990 xmlBufferFree(in->buffer);
1991 in->buffer = NULL;
1992 }
1993
Owen Taylor3473f882001-02-23 17:55:21 +00001994 xmlFree(in);
1995}
1996
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001997#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001998/**
1999 * xmlOutputBufferClose:
2000 * @out: a buffered output
2001 *
2002 * flushes and close the output I/O channel
2003 * and free up all the associated resources
2004 *
2005 * Returns the number of byte written or -1 in case of error.
2006 */
2007int
Daniel Veillard828ce832003-10-08 19:19:10 +00002008xmlOutputBufferClose(xmlOutputBufferPtr out)
2009{
Owen Taylor3473f882001-02-23 17:55:21 +00002010 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002011 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002012
2013 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002014 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002015 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002016 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002017 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002018 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002019 }
2020 written = out->written;
2021 if (out->conv) {
2022 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002023 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002024 }
2025 if (out->encoder != NULL) {
2026 xmlCharEncCloseFunc(out->encoder);
2027 }
2028 if (out->buffer != NULL) {
2029 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002030 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002031 }
2032
Daniel Veillard828ce832003-10-08 19:19:10 +00002033 if (out->error)
2034 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002035 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002036 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002037}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002038#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002039
2040/**
2041 * xmlParserInputBufferCreateFilename:
2042 * @URI: a C string containing the URI or filename
2043 * @enc: the charset encoding if known
2044 *
2045 * Create a buffered parser input for the progressive parsing of a file
2046 * If filename is "-' then we use stdin as the input.
2047 * Automatic support for ZLIB/Compress compressed document is provided
2048 * by default if found at compile-time.
2049 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2050 *
2051 * Returns the new parser input or NULL
2052 */
2053xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00002054xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002055 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002056 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002057 void *context = NULL;
2058
2059 if (xmlInputCallbackInitialized == 0)
2060 xmlRegisterDefaultInputCallbacks();
2061
2062 if (URI == NULL) return(NULL);
2063
2064 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002065 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002066 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002067 */
2068 if (context == NULL) {
2069 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2070 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2071 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002072 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard388236f2001-07-08 18:35:48 +00002073 if (context != NULL)
2074 break;
2075 }
Owen Taylor3473f882001-02-23 17:55:21 +00002076 }
2077 }
2078 if (context == NULL) {
2079 return(NULL);
2080 }
2081
2082 /*
2083 * Allocate the Input buffer front-end.
2084 */
2085 ret = xmlAllocParserInputBuffer(enc);
2086 if (ret != NULL) {
2087 ret->context = context;
2088 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2089 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002090#ifdef HAVE_ZLIB_H
2091 if (xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) {
2092 if (((z_stream *)context)->avail_in > 4) {
2093 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002094 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002095 if (gzread(context, buff4, 4) == 4) {
2096 if (strncmp(buff4, cptr, 4) == 0)
2097 ret->compressed = 0;
2098 else
2099 ret->compressed = 1;
2100 gzrewind(context);
2101 }
2102 }
2103 }
2104#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002105 }
2106 return(ret);
2107}
2108
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002109#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002110/**
2111 * xmlOutputBufferCreateFilename:
2112 * @URI: a C string containing the URI or filename
2113 * @encoder: the encoding converter or NULL
2114 * @compression: the compression ration (0 none, 9 max).
2115 *
2116 * Create a buffered output for the progressive saving of a file
2117 * If filename is "-' then we use stdout as the output.
2118 * Automatic support for ZLIB/Compress compressed document is provided
2119 * by default if found at compile-time.
2120 * TODO: currently if compression is set, the library only support
2121 * writing to a local file.
2122 *
2123 * Returns the new output or NULL
2124 */
2125xmlOutputBufferPtr
2126xmlOutputBufferCreateFilename(const char *URI,
2127 xmlCharEncodingHandlerPtr encoder,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002128 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002129 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002130 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002131 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002132 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00002133
Daniel Veillard4432df22003-09-28 18:58:27 +00002134#ifdef LIBXML_HTTP_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002135 int is_http_uri = 0; /* Can't change if HTTP disabled */
Daniel Veillard4432df22003-09-28 18:58:27 +00002136#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002137
Owen Taylor3473f882001-02-23 17:55:21 +00002138 if (xmlOutputCallbackInitialized == 0)
2139 xmlRegisterDefaultOutputCallbacks();
2140
2141 if (URI == NULL) return(NULL);
2142
Daniel Veillardf012a642001-07-23 19:10:52 +00002143#ifdef LIBXML_HTTP_ENABLED
2144 /* Need to prevent HTTP URI's from falling into zlib short circuit */
2145
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002146 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00002147#endif
2148
Owen Taylor3473f882001-02-23 17:55:21 +00002149
2150 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002151 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002152 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002153 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002154 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002155 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002156 if (unescaped != NULL) {
2157#ifdef HAVE_ZLIB_H
2158 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
2159 context = xmlGzfileOpenW(unescaped, compression);
2160 if (context != NULL) {
2161 ret = xmlAllocOutputBuffer(encoder);
2162 if (ret != NULL) {
2163 ret->context = context;
2164 ret->writecallback = xmlGzfileWrite;
2165 ret->closecallback = xmlGzfileClose;
2166 }
2167 xmlFree(unescaped);
2168 return(ret);
2169 }
2170 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002171#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002172 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2173 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2174 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2175#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2176 /* Need to pass compression parameter into HTTP open calls */
2177 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2178 context = xmlIOHTTPOpenW(unescaped, compression);
2179 else
2180#endif
2181 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2182 if (context != NULL)
2183 break;
2184 }
2185 }
2186 xmlFree(unescaped);
2187 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002188
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002189 /*
2190 * If this failed try with a non-escaped URI this may be a strange
2191 * filename
2192 */
2193 if (context == NULL) {
2194#ifdef HAVE_ZLIB_H
2195 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002196 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002197 if (context != NULL) {
2198 ret = xmlAllocOutputBuffer(encoder);
2199 if (ret != NULL) {
2200 ret->context = context;
2201 ret->writecallback = xmlGzfileWrite;
2202 ret->closecallback = xmlGzfileClose;
2203 }
2204 return(ret);
2205 }
2206 }
2207#endif
2208 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2209 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002210 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002211#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2212 /* Need to pass compression parameter into HTTP open calls */
2213 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2214 context = xmlIOHTTPOpenW(URI, compression);
2215 else
2216#endif
2217 context = xmlOutputCallbackTable[i].opencallback(URI);
2218 if (context != NULL)
2219 break;
2220 }
Owen Taylor3473f882001-02-23 17:55:21 +00002221 }
2222 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002223
Owen Taylor3473f882001-02-23 17:55:21 +00002224 if (context == NULL) {
2225 return(NULL);
2226 }
2227
2228 /*
2229 * Allocate the Output buffer front-end.
2230 */
2231 ret = xmlAllocOutputBuffer(encoder);
2232 if (ret != NULL) {
2233 ret->context = context;
2234 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2235 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2236 }
2237 return(ret);
2238}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002239#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002240
2241/**
2242 * xmlParserInputBufferCreateFile:
2243 * @file: a FILE*
2244 * @enc: the charset encoding if known
2245 *
2246 * Create a buffered parser input for the progressive parsing of a FILE *
2247 * buffered C I/O
2248 *
2249 * Returns the new parser input or NULL
2250 */
2251xmlParserInputBufferPtr
2252xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2253 xmlParserInputBufferPtr ret;
2254
2255 if (xmlInputCallbackInitialized == 0)
2256 xmlRegisterDefaultInputCallbacks();
2257
2258 if (file == NULL) return(NULL);
2259
2260 ret = xmlAllocParserInputBuffer(enc);
2261 if (ret != NULL) {
2262 ret->context = file;
2263 ret->readcallback = xmlFileRead;
2264 ret->closecallback = xmlFileFlush;
2265 }
2266
2267 return(ret);
2268}
2269
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002270#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002271/**
2272 * xmlOutputBufferCreateFile:
2273 * @file: a FILE*
2274 * @encoder: the encoding converter or NULL
2275 *
2276 * Create a buffered output for the progressive saving to a FILE *
2277 * buffered C I/O
2278 *
2279 * Returns the new parser output or NULL
2280 */
2281xmlOutputBufferPtr
2282xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2283 xmlOutputBufferPtr ret;
2284
2285 if (xmlOutputCallbackInitialized == 0)
2286 xmlRegisterDefaultOutputCallbacks();
2287
2288 if (file == NULL) return(NULL);
2289
2290 ret = xmlAllocOutputBuffer(encoder);
2291 if (ret != NULL) {
2292 ret->context = file;
2293 ret->writecallback = xmlFileWrite;
2294 ret->closecallback = xmlFileFlush;
2295 }
2296
2297 return(ret);
2298}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002299#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002300
2301/**
2302 * xmlParserInputBufferCreateFd:
2303 * @fd: a file descriptor number
2304 * @enc: the charset encoding if known
2305 *
2306 * Create a buffered parser input for the progressive parsing for the input
2307 * from a file descriptor
2308 *
2309 * Returns the new parser input or NULL
2310 */
2311xmlParserInputBufferPtr
2312xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2313 xmlParserInputBufferPtr ret;
2314
2315 if (fd < 0) return(NULL);
2316
2317 ret = xmlAllocParserInputBuffer(enc);
2318 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002319 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002320 ret->readcallback = xmlFdRead;
2321 ret->closecallback = xmlFdClose;
2322 }
2323
2324 return(ret);
2325}
2326
2327/**
2328 * xmlParserInputBufferCreateMem:
2329 * @mem: the memory input
2330 * @size: the length of the memory block
2331 * @enc: the charset encoding if known
2332 *
2333 * Create a buffered parser input for the progressive parsing for the input
2334 * from a memory area.
2335 *
2336 * Returns the new parser input or NULL
2337 */
2338xmlParserInputBufferPtr
2339xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2340 xmlParserInputBufferPtr ret;
2341
2342 if (size <= 0) return(NULL);
2343 if (mem == NULL) return(NULL);
2344
2345 ret = xmlAllocParserInputBuffer(enc);
2346 if (ret != NULL) {
2347 ret->context = (void *) mem;
2348 ret->readcallback = (xmlInputReadCallback) xmlNop;
2349 ret->closecallback = NULL;
2350 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2351 }
2352
2353 return(ret);
2354}
2355
2356/**
Daniel Veillard53350552003-09-18 13:35:51 +00002357 * xmlParserInputBufferCreateStatic:
2358 * @mem: the memory input
2359 * @size: the length of the memory block
2360 * @enc: the charset encoding if known
2361 *
2362 * Create a buffered parser input for the progressive parsing for the input
2363 * from an immutable memory area. This will not copy the memory area to
2364 * the buffer, but the memory is expected to be available until the end of
2365 * the parsing, this is useful for example when using mmap'ed file.
2366 *
2367 * Returns the new parser input or NULL
2368 */
2369xmlParserInputBufferPtr
2370xmlParserInputBufferCreateStatic(const char *mem, int size,
2371 xmlCharEncoding enc) {
2372 xmlParserInputBufferPtr ret;
2373
2374 if (size <= 0) return(NULL);
2375 if (mem == NULL) return(NULL);
2376
2377 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2378 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002379 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002380 return(NULL);
2381 }
2382 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002383 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002384 if (ret->buffer == NULL) {
2385 xmlFree(ret);
2386 return(NULL);
2387 }
2388 ret->encoder = xmlGetCharEncodingHandler(enc);
2389 if (ret->encoder != NULL)
2390 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2391 else
2392 ret->raw = NULL;
2393 ret->compressed = -1;
2394 ret->context = (void *) mem;
2395 ret->readcallback = NULL;
2396 ret->closecallback = NULL;
2397
2398 return(ret);
2399}
2400
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002401#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002402/**
Owen Taylor3473f882001-02-23 17:55:21 +00002403 * xmlOutputBufferCreateFd:
2404 * @fd: a file descriptor number
2405 * @encoder: the encoding converter or NULL
2406 *
2407 * Create a buffered output for the progressive saving
2408 * to a file descriptor
2409 *
2410 * Returns the new parser output or NULL
2411 */
2412xmlOutputBufferPtr
2413xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2414 xmlOutputBufferPtr ret;
2415
2416 if (fd < 0) return(NULL);
2417
2418 ret = xmlAllocOutputBuffer(encoder);
2419 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002420 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002421 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002422 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002423 }
2424
2425 return(ret);
2426}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002427#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002428
2429/**
2430 * xmlParserInputBufferCreateIO:
2431 * @ioread: an I/O read function
2432 * @ioclose: an I/O close function
2433 * @ioctx: an I/O handler
2434 * @enc: the charset encoding if known
2435 *
2436 * Create a buffered parser input for the progressive parsing for the input
2437 * from an I/O handler
2438 *
2439 * Returns the new parser input or NULL
2440 */
2441xmlParserInputBufferPtr
2442xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2443 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2444 xmlParserInputBufferPtr ret;
2445
2446 if (ioread == NULL) return(NULL);
2447
2448 ret = xmlAllocParserInputBuffer(enc);
2449 if (ret != NULL) {
2450 ret->context = (void *) ioctx;
2451 ret->readcallback = ioread;
2452 ret->closecallback = ioclose;
2453 }
2454
2455 return(ret);
2456}
2457
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002458#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002459/**
2460 * xmlOutputBufferCreateIO:
2461 * @iowrite: an I/O write function
2462 * @ioclose: an I/O close function
2463 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002464 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002465 *
2466 * Create a buffered output for the progressive saving
2467 * to an I/O handler
2468 *
2469 * Returns the new parser output or NULL
2470 */
2471xmlOutputBufferPtr
2472xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2473 xmlOutputCloseCallback ioclose, void *ioctx,
2474 xmlCharEncodingHandlerPtr encoder) {
2475 xmlOutputBufferPtr ret;
2476
2477 if (iowrite == NULL) return(NULL);
2478
2479 ret = xmlAllocOutputBuffer(encoder);
2480 if (ret != NULL) {
2481 ret->context = (void *) ioctx;
2482 ret->writecallback = iowrite;
2483 ret->closecallback = ioclose;
2484 }
2485
2486 return(ret);
2487}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002488#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002489
2490/**
2491 * xmlParserInputBufferPush:
2492 * @in: a buffered parser input
2493 * @len: the size in bytes of the array.
2494 * @buf: an char array
2495 *
2496 * Push the content of the arry in the input buffer
2497 * This routine handle the I18N transcoding to internal UTF-8
2498 * This is used when operating the parser in progressive (push) mode.
2499 *
2500 * Returns the number of chars read and stored in the buffer, or -1
2501 * in case of error.
2502 */
2503int
2504xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2505 int len, const char *buf) {
2506 int nbchars = 0;
2507
2508 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002509 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002510 if (in->encoder != NULL) {
2511 /*
2512 * Store the data in the incoming raw buffer
2513 */
2514 if (in->raw == NULL) {
2515 in->raw = xmlBufferCreate();
2516 }
2517 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2518
2519 /*
2520 * convert as much as possible to the parser reading buffer.
2521 */
2522 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2523 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002524 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002525 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002526 return(-1);
2527 }
2528 } else {
2529 nbchars = len;
2530 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2531 }
2532#ifdef DEBUG_INPUT
2533 xmlGenericError(xmlGenericErrorContext,
2534 "I/O: pushed %d chars, buffer %d/%d\n",
2535 nbchars, in->buffer->use, in->buffer->size);
2536#endif
2537 return(nbchars);
2538}
2539
2540/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002541 * endOfInput:
2542 *
2543 * When reading from an Input channel indicated end of file or error
2544 * don't reread from it again.
2545 */
2546static int
2547endOfInput (void * context ATTRIBUTE_UNUSED,
2548 char * buffer ATTRIBUTE_UNUSED,
2549 int len ATTRIBUTE_UNUSED) {
2550 return(0);
2551}
2552
2553/**
Owen Taylor3473f882001-02-23 17:55:21 +00002554 * xmlParserInputBufferGrow:
2555 * @in: a buffered parser input
2556 * @len: indicative value of the amount of chars to read
2557 *
2558 * Grow up the content of the input buffer, the old data are preserved
2559 * This routine handle the I18N transcoding to internal UTF-8
2560 * This routine is used when operating the parser in normal (pull) mode
2561 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002562 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002563 * onto in->buffer or in->raw
2564 *
2565 * Returns the number of chars read and stored in the buffer, or -1
2566 * in case of error.
2567 */
2568int
2569xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2570 char *buffer = NULL;
2571 int res = 0;
2572 int nbchars = 0;
2573 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002574 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002575
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002576 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002577 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002578 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002579
Owen Taylor3473f882001-02-23 17:55:21 +00002580 buffree = in->buffer->size - in->buffer->use;
2581 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002582 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002583 in->error = XML_IO_BUFFER_FULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002584 return(0);
2585 }
Owen Taylor3473f882001-02-23 17:55:21 +00002586
Daniel Veillarde5354492002-05-16 08:43:22 +00002587 needSize = in->buffer->use + len + 1;
2588 if (needSize > in->buffer->size){
2589 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002590 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002591 in->error = XML_ERR_NO_MEMORY;
Daniel Veillarde5354492002-05-16 08:43:22 +00002592 return(0);
2593 }
Owen Taylor3473f882001-02-23 17:55:21 +00002594 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002595 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002596
2597 /*
2598 * Call the read method for this I/O type.
2599 */
2600 if (in->readcallback != NULL) {
2601 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002602 if (res <= 0)
2603 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002604 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002605 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002606 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002607 return(-1);
2608 }
2609 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002610 return(-1);
2611 }
2612 len = res;
2613 if (in->encoder != NULL) {
2614 /*
2615 * Store the data in the incoming raw buffer
2616 */
2617 if (in->raw == NULL) {
2618 in->raw = xmlBufferCreate();
2619 }
2620 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2621
2622 /*
2623 * convert as much as possible to the parser reading buffer.
2624 */
2625 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2626 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002627 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002628 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002629 return(-1);
2630 }
2631 } else {
2632 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002633 in->buffer->use += nbchars;
2634 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002635 }
2636#ifdef DEBUG_INPUT
2637 xmlGenericError(xmlGenericErrorContext,
2638 "I/O: read %d chars, buffer %d/%d\n",
2639 nbchars, in->buffer->use, in->buffer->size);
2640#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002641 return(nbchars);
2642}
2643
2644/**
2645 * xmlParserInputBufferRead:
2646 * @in: a buffered parser input
2647 * @len: indicative value of the amount of chars to read
2648 *
2649 * Refresh the content of the input buffer, the old data are considered
2650 * consumed
2651 * This routine handle the I18N transcoding to internal UTF-8
2652 *
2653 * Returns the number of chars read and stored in the buffer, or -1
2654 * in case of error.
2655 */
2656int
2657xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002658 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002659 if (in->readcallback != NULL)
2660 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002661 else if ((in->buffer != NULL) &&
2662 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2663 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002664 else
2665 return(-1);
2666}
2667
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002668#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002669/**
2670 * xmlOutputBufferWrite:
2671 * @out: a buffered parser output
2672 * @len: the size in bytes of the array.
2673 * @buf: an char array
2674 *
2675 * Write the content of the array in the output I/O buffer
2676 * This routine handle the I18N transcoding from internal UTF-8
2677 * The buffer is lossless, i.e. will store in case of partial
2678 * or delayed writes.
2679 *
2680 * Returns the number of chars immediately written, or -1
2681 * in case of error.
2682 */
2683int
2684xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2685 int nbchars = 0; /* number of chars to output to I/O */
2686 int ret; /* return from function call */
2687 int written = 0; /* number of char written to I/O so far */
2688 int chunk; /* number of byte curreent processed from buf */
2689
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002690 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002691 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002692 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002693
2694 do {
2695 chunk = len;
2696 if (chunk > 4 * MINLEN)
2697 chunk = 4 * MINLEN;
2698
2699 /*
2700 * first handle encoding stuff.
2701 */
2702 if (out->encoder != NULL) {
2703 /*
2704 * Store the data in the incoming raw buffer
2705 */
2706 if (out->conv == NULL) {
2707 out->conv = xmlBufferCreate();
2708 }
2709 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2710
2711 if ((out->buffer->use < MINLEN) && (chunk == len))
2712 goto done;
2713
2714 /*
2715 * convert as much as possible to the parser reading buffer.
2716 */
2717 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002718 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002719 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002720 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002721 return(-1);
2722 }
2723 nbchars = out->conv->use;
2724 } else {
2725 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2726 nbchars = out->buffer->use;
2727 }
2728 buf += chunk;
2729 len -= chunk;
2730
2731 if ((nbchars < MINLEN) && (len <= 0))
2732 goto done;
2733
2734 if (out->writecallback) {
2735 /*
2736 * second write the stuff to the I/O channel
2737 */
2738 if (out->encoder != NULL) {
2739 ret = out->writecallback(out->context,
2740 (const char *)out->conv->content, nbchars);
2741 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002742 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002743 } else {
2744 ret = out->writecallback(out->context,
2745 (const char *)out->buffer->content, nbchars);
2746 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002747 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002748 }
2749 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002750 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002751 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002752 return(ret);
2753 }
2754 out->written += ret;
2755 }
2756 written += nbchars;
2757 } while (len > 0);
2758
2759done:
2760#ifdef DEBUG_INPUT
2761 xmlGenericError(xmlGenericErrorContext,
2762 "I/O: wrote %d chars\n", written);
2763#endif
2764 return(written);
2765}
2766
2767/**
2768 * xmlOutputBufferWriteString:
2769 * @out: a buffered parser output
2770 * @str: a zero terminated C string
2771 *
2772 * Write the content of the string in the output I/O buffer
2773 * This routine handle the I18N transcoding from internal UTF-8
2774 * The buffer is lossless, i.e. will store in case of partial
2775 * or delayed writes.
2776 *
2777 * Returns the number of chars immediately written, or -1
2778 * in case of error.
2779 */
2780int
2781xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2782 int len;
2783
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002784 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002785 if (str == NULL)
2786 return(-1);
2787 len = strlen(str);
2788
2789 if (len > 0)
2790 return(xmlOutputBufferWrite(out, len, str));
2791 return(len);
2792}
2793
2794/**
2795 * xmlOutputBufferFlush:
2796 * @out: a buffered output
2797 *
2798 * flushes the output I/O channel
2799 *
2800 * Returns the number of byte written or -1 in case of error.
2801 */
2802int
2803xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2804 int nbchars = 0, ret = 0;
2805
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002806 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002807 /*
2808 * first handle encoding stuff.
2809 */
2810 if ((out->conv != NULL) && (out->encoder != NULL)) {
2811 /*
2812 * convert as much as possible to the parser reading buffer.
2813 */
2814 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2815 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002816 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002817 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002818 return(-1);
2819 }
2820 }
2821
2822 /*
2823 * second flush the stuff to the I/O channel
2824 */
2825 if ((out->conv != NULL) && (out->encoder != NULL) &&
2826 (out->writecallback != NULL)) {
2827 ret = out->writecallback(out->context,
2828 (const char *)out->conv->content, out->conv->use);
2829 if (ret >= 0)
2830 xmlBufferShrink(out->conv, ret);
2831 } else if (out->writecallback != NULL) {
2832 ret = out->writecallback(out->context,
2833 (const char *)out->buffer->content, out->buffer->use);
2834 if (ret >= 0)
2835 xmlBufferShrink(out->buffer, ret);
2836 }
2837 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002838 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002839 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00002840 return(ret);
2841 }
2842 out->written += ret;
2843
2844#ifdef DEBUG_INPUT
2845 xmlGenericError(xmlGenericErrorContext,
2846 "I/O: flushed %d chars\n", ret);
2847#endif
2848 return(ret);
2849}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002850#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002851
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002852/**
Owen Taylor3473f882001-02-23 17:55:21 +00002853 * xmlParserGetDirectory:
2854 * @filename: the path to a file
2855 *
2856 * lookup the directory for that file
2857 *
2858 * Returns a new allocated string containing the directory, or NULL.
2859 */
2860char *
2861xmlParserGetDirectory(const char *filename) {
2862 char *ret = NULL;
2863 char dir[1024];
2864 char *cur;
2865 char sep = '/';
2866
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002867#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2868 return NULL;
2869#endif
2870
Owen Taylor3473f882001-02-23 17:55:21 +00002871 if (xmlInputCallbackInitialized == 0)
2872 xmlRegisterDefaultInputCallbacks();
2873
2874 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002875#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002876 sep = '\\';
2877#endif
2878
2879 strncpy(dir, filename, 1023);
2880 dir[1023] = 0;
2881 cur = &dir[strlen(dir)];
2882 while (cur > dir) {
2883 if (*cur == sep) break;
2884 cur --;
2885 }
2886 if (*cur == sep) {
2887 if (cur == dir) dir[1] = 0;
2888 else *cur = 0;
2889 ret = xmlMemStrdup(dir);
2890 } else {
2891 if (getcwd(dir, 1024) != NULL) {
2892 dir[1023] = 0;
2893 ret = xmlMemStrdup(dir);
2894 }
2895 }
2896 return(ret);
2897}
2898
2899/****************************************************************
2900 * *
2901 * External entities loading *
2902 * *
2903 ****************************************************************/
2904
Daniel Veillard561b7f82002-03-20 21:55:57 +00002905static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002906#ifdef HAVE_STAT
2907 int ret;
2908 struct stat info;
2909 const char *path;
2910
2911 if (URL == NULL)
2912 return(0);
2913
Daniel Veillardf4862f02002-09-10 11:13:43 +00002914 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002915#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002916 path = &URL[17];
2917#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002918 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002919#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002920 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002921#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002922 path = &URL[8];
2923#else
2924 path = &URL[7];
2925#endif
2926 } else
2927 path = URL;
2928 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002929 if (ret == 0)
2930 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002931#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002932 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002933}
Daniel Veillard6990bf32001-08-23 21:17:48 +00002934
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002935/**
Owen Taylor3473f882001-02-23 17:55:21 +00002936 * xmlDefaultExternalEntityLoader:
2937 * @URL: the URL for the entity to load
2938 * @ID: the System ID for the entity to load
2939 * @ctxt: the context in which the entity is called or NULL
2940 *
2941 * By default we don't load external entitites, yet.
2942 *
2943 * Returns a new allocated xmlParserInputPtr, or NULL.
2944 */
2945static
2946xmlParserInputPtr
2947xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2948 xmlParserCtxtPtr ctxt) {
2949 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002950 xmlChar *resource = NULL;
2951#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002952 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002953#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002954
2955#ifdef DEBUG_EXTERNAL_ENTITIES
2956 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002957 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002958#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002959#ifdef LIBXML_CATALOG_ENABLED
2960 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002961 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002962 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002963 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002964 pref = xmlCatalogGetDefaults();
2965
Daniel Veillard561b7f82002-03-20 21:55:57 +00002966 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002967 /*
2968 * Do a local lookup
2969 */
2970 if ((ctxt->catalogs != NULL) &&
2971 ((pref == XML_CATA_ALLOW_ALL) ||
2972 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2973 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2974 (const xmlChar *)ID,
2975 (const xmlChar *)URL);
2976 }
2977 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002978 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002979 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002980 if ((resource == NULL) &&
2981 ((pref == XML_CATA_ALLOW_ALL) ||
2982 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002983 resource = xmlCatalogResolve((const xmlChar *)ID,
2984 (const xmlChar *)URL);
2985 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002986 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002987 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002988
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002989 /*
2990 * TODO: do an URI lookup on the reference
2991 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002992 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002993 xmlChar *tmp = NULL;
2994
2995 if ((ctxt->catalogs != NULL) &&
2996 ((pref == XML_CATA_ALLOW_ALL) ||
2997 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2998 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2999 }
3000 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003001 ((pref == XML_CATA_ALLOW_ALL) ||
3002 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003003 tmp = xmlCatalogResolveURI(resource);
3004 }
3005
3006 if (tmp != NULL) {
3007 xmlFree(resource);
3008 resource = tmp;
3009 }
3010 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003011 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003012#endif
3013
3014 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003015 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003016
3017 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00003018 if (ID == NULL)
3019 ID = "NULL";
Daniel Veillardcd6ff282003-10-08 22:38:13 +00003020 xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Owen Taylor3473f882001-02-23 17:55:21 +00003021 return(NULL);
3022 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003023 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00003024 if (ret == NULL) {
Daniel Veillardcd6ff282003-10-08 22:38:13 +00003025 xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n",
3026 (const char *) resource);
Owen Taylor3473f882001-02-23 17:55:21 +00003027 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003028 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003029 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00003030 return(ret);
3031}
3032
3033static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3034 xmlDefaultExternalEntityLoader;
3035
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003036/**
Owen Taylor3473f882001-02-23 17:55:21 +00003037 * xmlSetExternalEntityLoader:
3038 * @f: the new entity resolver function
3039 *
3040 * Changes the defaultexternal entity resolver function for the application
3041 */
3042void
3043xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3044 xmlCurrentExternalEntityLoader = f;
3045}
3046
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003047/**
Owen Taylor3473f882001-02-23 17:55:21 +00003048 * xmlGetExternalEntityLoader:
3049 *
3050 * Get the default external entity resolver function for the application
3051 *
3052 * Returns the xmlExternalEntityLoader function pointer
3053 */
3054xmlExternalEntityLoader
3055xmlGetExternalEntityLoader(void) {
3056 return(xmlCurrentExternalEntityLoader);
3057}
3058
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003059/**
Owen Taylor3473f882001-02-23 17:55:21 +00003060 * xmlLoadExternalEntity:
3061 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003062 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003063 * @ctxt: the context in which the entity is called or NULL
3064 *
3065 * Load an external entity, note that the use of this function for
3066 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003067 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003068 *
3069 * Returns the xmlParserInputPtr or NULL
3070 */
3071xmlParserInputPtr
3072xmlLoadExternalEntity(const char *URL, const char *ID,
3073 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003074 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3075 char *canonicFilename;
3076 xmlParserInputPtr ret;
3077
3078 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3079 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003080 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003081 return(NULL);
3082 }
3083
3084 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3085 xmlFree(canonicFilename);
3086 return(ret);
3087 }
Owen Taylor3473f882001-02-23 17:55:21 +00003088 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3089}
3090
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003091/************************************************************************
3092 * *
3093 * Disabling Network access *
3094 * *
3095 ************************************************************************/
3096
3097#ifdef LIBXML_CATALOG_ENABLED
3098static int
3099xmlNoNetExists(const char *URL)
3100{
3101#ifdef HAVE_STAT
3102 int ret;
3103 struct stat info;
3104 const char *path;
3105
3106 if (URL == NULL)
3107 return (0);
3108
Daniel Veillardf4862f02002-09-10 11:13:43 +00003109 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003110#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003111 path = &URL[17];
3112#else
3113 path = &URL[16];
3114#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003115 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003116#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003117 path = &URL[8];
3118#else
3119 path = &URL[7];
3120#endif
3121 } else
3122 path = URL;
3123 ret = stat(path, &info);
3124 if (ret == 0)
3125 return (1);
3126#endif
3127 return (0);
3128}
3129#endif
3130
3131/**
3132 * xmlNoNetExternalEntityLoader:
3133 * @URL: the URL for the entity to load
3134 * @ID: the System ID for the entity to load
3135 * @ctxt: the context in which the entity is called or NULL
3136 *
3137 * A specific entity loader disabling network accesses, though still
3138 * allowing local catalog accesses for resolution.
3139 *
3140 * Returns a new allocated xmlParserInputPtr, or NULL.
3141 */
3142xmlParserInputPtr
3143xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3144 xmlParserCtxtPtr ctxt) {
3145 xmlParserInputPtr input = NULL;
3146 xmlChar *resource = NULL;
3147
3148#ifdef LIBXML_CATALOG_ENABLED
3149 xmlCatalogAllow pref;
3150
3151 /*
3152 * If the resource doesn't exists as a file,
3153 * try to load it from the resource pointed in the catalogs
3154 */
3155 pref = xmlCatalogGetDefaults();
3156
3157 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3158 /*
3159 * Do a local lookup
3160 */
3161 if ((ctxt->catalogs != NULL) &&
3162 ((pref == XML_CATA_ALLOW_ALL) ||
3163 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3164 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3165 (const xmlChar *)ID,
3166 (const xmlChar *)URL);
3167 }
3168 /*
3169 * Try a global lookup
3170 */
3171 if ((resource == NULL) &&
3172 ((pref == XML_CATA_ALLOW_ALL) ||
3173 (pref == XML_CATA_ALLOW_GLOBAL))) {
3174 resource = xmlCatalogResolve((const xmlChar *)ID,
3175 (const xmlChar *)URL);
3176 }
3177 if ((resource == NULL) && (URL != NULL))
3178 resource = xmlStrdup((const xmlChar *) URL);
3179
3180 /*
3181 * TODO: do an URI lookup on the reference
3182 */
3183 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3184 xmlChar *tmp = NULL;
3185
3186 if ((ctxt->catalogs != NULL) &&
3187 ((pref == XML_CATA_ALLOW_ALL) ||
3188 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3189 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3190 }
3191 if ((tmp == NULL) &&
3192 ((pref == XML_CATA_ALLOW_ALL) ||
3193 (pref == XML_CATA_ALLOW_GLOBAL))) {
3194 tmp = xmlCatalogResolveURI(resource);
3195 }
3196
3197 if (tmp != NULL) {
3198 xmlFree(resource);
3199 resource = tmp;
3200 }
3201 }
3202 }
3203#endif
3204 if (resource == NULL)
3205 resource = (xmlChar *) URL;
3206
3207 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003208 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3209 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003210 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003211 if (resource != (xmlChar *) URL)
3212 xmlFree(resource);
3213 return(NULL);
3214 }
3215 }
3216 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3217 if (resource != (xmlChar *) URL)
3218 xmlFree(resource);
3219 return(input);
3220}
3221