blob: fa6f37db1693c984adf3029a6ddf43c6f47d91f1 [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
108/*
109 * Output I/O callback sets
110 */
111typedef struct _xmlOutputCallback {
112 xmlOutputMatchCallback matchcallback;
113 xmlOutputOpenCallback opencallback;
114 xmlOutputWriteCallback writecallback;
115 xmlOutputCloseCallback closecallback;
116} xmlOutputCallback;
117
118#define MAX_OUTPUT_CALLBACK 15
119
Daniel Veillard22090732001-07-16 00:06:07 +0000120static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
121static int xmlOutputCallbackNr = 0;
122static int xmlOutputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000123
Daniel Veillardf4862f02002-09-10 11:13:43 +0000124/************************************************************************
125 * *
126 * Handling of Windows file paths *
127 * *
128 ************************************************************************/
129
130#define IS_WINDOWS_PATH(p) \
131 ((p != NULL) && \
132 (((p[0] >= 'a') && (p[0] <= 'z')) || \
133 ((p[0] >= 'A') && (p[0] <= 'Z'))) && \
134 (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
135
136
137/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000138 * xmlNormalizeWindowsPath:
Daniel Veillardf4862f02002-09-10 11:13:43 +0000139 * @path: a windows path like "C:/foo/bar"
140 *
141 * Normalize a Windows path to make an URL from it
142 *
143 * Returns a new URI which must be freed by the caller or NULL
144 * in case of error
145 */
146xmlChar *
147xmlNormalizeWindowsPath(const xmlChar *path)
148{
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000149 int len, i = 0, j;
Daniel Veillardf4862f02002-09-10 11:13:43 +0000150 xmlChar *ret;
151
152 if (path == NULL)
153 return(NULL);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000154
155 len = xmlStrlen(path);
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000156 if (!IS_WINDOWS_PATH(path)) {
157 ret = xmlStrdup(path);
158 if (ret == NULL)
159 return(NULL);
160 j = 0;
161 } else {
162 ret = xmlMalloc(len + 10);
163 if (ret == NULL)
164 return(NULL);
165 ret[0] = 'f';
166 ret[1] = 'i';
167 ret[2] = 'l';
168 ret[3] = 'e';
169 ret[4] = ':';
170 ret[5] = '/';
171 ret[6] = '/';
172 ret[7] = '/';
173 j = 8;
174 }
Daniel Veillardf4862f02002-09-10 11:13:43 +0000175
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000176 while (i < len) {
Daniel Veillardf4862f02002-09-10 11:13:43 +0000177 /* TODO: UTF8 conversion + URI escaping ??? */
178 if (path[i] == '\\')
179 ret[j] = '/';
180 else
181 ret[j] = path[i];
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000182 i++;
183 j++;
Daniel Veillardf4862f02002-09-10 11:13:43 +0000184 }
185 ret[j] = 0;
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000186
Daniel Veillardf4862f02002-09-10 11:13:43 +0000187 return(ret);
188}
189
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000190/**
191 * xmlCleanupInputCallbacks:
192 *
193 * clears the entire input callback table. this includes the
194 * compiled-in I/O.
195 */
196void
197xmlCleanupInputCallbacks(void)
198{
199 int i;
200
201 if (!xmlInputCallbackInitialized)
202 return;
203
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000204 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000205 xmlInputCallbackTable[i].matchcallback = NULL;
206 xmlInputCallbackTable[i].opencallback = NULL;
207 xmlInputCallbackTable[i].readcallback = NULL;
208 xmlInputCallbackTable[i].closecallback = NULL;
209 }
Daniel Veillard9e412302002-06-10 15:59:44 +0000210 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000211
212 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000213 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000214}
215
216/**
217 * xmlCleanupOutputCallbacks:
218 *
219 * clears the entire output callback table. this includes the
220 * compiled-in I/O callbacks.
221 */
222void
223xmlCleanupOutputCallbacks(void)
224{
225 int i;
226
227 if (!xmlOutputCallbackInitialized)
228 return;
229
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000230 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000231 xmlOutputCallbackTable[i].matchcallback = NULL;
232 xmlOutputCallbackTable[i].opencallback = NULL;
233 xmlOutputCallbackTable[i].writecallback = NULL;
234 xmlOutputCallbackTable[i].closecallback = NULL;
235 }
Daniel Veillard9e412302002-06-10 15:59:44 +0000236 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000237
238 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000239 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000240}
241
Owen Taylor3473f882001-02-23 17:55:21 +0000242/************************************************************************
243 * *
244 * Standard I/O for file accesses *
245 * *
246 ************************************************************************/
247
248/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000249 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000250 * @path: the path to check
251 *
252 * function checks to see if @path is a valid source
253 * (file, socket...) for XML.
254 *
255 * if stat is not available on the target machine,
256 * returns 1. if stat fails, returns 0 (if calling
257 * stat on the filename fails, it can't be right).
258 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000259 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000260 */
261
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000262int
Owen Taylor3473f882001-02-23 17:55:21 +0000263xmlCheckFilename (const char *path)
264{
265#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000266 struct stat stat_buffer;
267
268 if (stat(path, &stat_buffer) == -1)
269 return 0;
270
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000271#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000272 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000273 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000274 }
Owen Taylor3473f882001-02-23 17:55:21 +0000275#endif
276#endif
277 return 1;
278}
279
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000280static int
Owen Taylor3473f882001-02-23 17:55:21 +0000281xmlNop(void) {
282 return(0);
283}
284
285/**
Owen Taylor3473f882001-02-23 17:55:21 +0000286 * xmlFdRead:
287 * @context: the I/O context
288 * @buffer: where to drop data
289 * @len: number of bytes to read
290 *
291 * Read @len bytes to @buffer from the I/O channel.
292 *
293 * Returns the number of bytes written
294 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000295static int
Owen Taylor3473f882001-02-23 17:55:21 +0000296xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000297 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000298}
299
300/**
301 * xmlFdWrite:
302 * @context: the I/O context
303 * @buffer: where to get data
304 * @len: number of bytes to write
305 *
306 * Write @len bytes from @buffer to the I/O channel.
307 *
308 * Returns the number of bytes written
309 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000310static int
Owen Taylor3473f882001-02-23 17:55:21 +0000311xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000312 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000313}
314
315/**
316 * xmlFdClose:
317 * @context: the I/O context
318 *
319 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000320 *
321 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000322 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000323static int
Owen Taylor3473f882001-02-23 17:55:21 +0000324xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000325 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000326}
327
328/**
329 * xmlFileMatch:
330 * @filename: the URI for matching
331 *
332 * input from FILE *
333 *
334 * Returns 1 if matches, 0 otherwise
335 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000336int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000337xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000338 return(1);
339}
340
341/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000342 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000343 * @filename: the URI for matching
344 *
345 * input from FILE *, supports compressed input
346 * if @filename is " " then the standard input is used
347 *
348 * Returns an I/O context or NULL in case of error
349 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000350static void *
351xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000352 const char *path = NULL;
353 FILE *fd;
354
355 if (!strcmp(filename, "-")) {
356 fd = stdin;
357 return((void *) fd);
358 }
359
Daniel Veillardf4862f02002-09-10 11:13:43 +0000360 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000361#if defined (_WIN32) && !defined(__CYGWIN__)
362 path = &filename[17];
363#else
Owen Taylor3473f882001-02-23 17:55:21 +0000364 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000365#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000366 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000367#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000368 path = &filename[8];
369#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000370 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000371#endif
372 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000373 path = filename;
374
375 if (path == NULL)
376 return(NULL);
377 if (!xmlCheckFilename(path))
378 return(NULL);
379
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000380#if defined(WIN32) || defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000381 fd = fopen(path, "rb");
382#else
383 fd = fopen(path, "r");
384#endif /* WIN32 */
385 return((void *) fd);
386}
387
388/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000389 * xmlFileOpen:
390 * @filename: the URI for matching
391 *
392 * Wrapper around xmlFileOpen_real that try it with an unescaped
393 * version of @filename, if this fails fallback to @filename
394 */
395void *
396xmlFileOpen (const char *filename) {
397 char *unescaped;
398 void *retval;
399 unescaped = xmlURIUnescapeString(filename, 0, NULL);
400 if (unescaped != NULL) {
401 retval = xmlFileOpen_real(unescaped);
402 } else {
403 retval = xmlFileOpen_real(filename);
404 }
405 xmlFree(unescaped);
406 return retval;
407}
408
409/**
Owen Taylor3473f882001-02-23 17:55:21 +0000410 * xmlFileOpenW:
411 * @filename: the URI for matching
412 *
413 * output to from FILE *,
414 * if @filename is "-" then the standard output is used
415 *
416 * Returns an I/O context or NULL in case of error
417 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000418static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000419xmlFileOpenW (const char *filename) {
420 const char *path = NULL;
421 FILE *fd;
422
423 if (!strcmp(filename, "-")) {
424 fd = stdout;
425 return((void *) fd);
426 }
427
Daniel Veillardf4862f02002-09-10 11:13:43 +0000428 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
429#if defined (_WIN32) && !defined(__CYGWIN__)
430 path = &filename[17];
431#else
Owen Taylor3473f882001-02-23 17:55:21 +0000432 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000433#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000434 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000435#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000436 path = &filename[8];
437#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000438 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000439#endif
440 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000441 path = filename;
442
443 if (path == NULL)
444 return(NULL);
445
446 fd = fopen(path, "w");
447 return((void *) fd);
448}
449
450/**
451 * xmlFileRead:
452 * @context: the I/O context
453 * @buffer: where to drop data
454 * @len: number of bytes to write
455 *
456 * Read @len bytes to @buffer from the I/O channel.
457 *
458 * Returns the number of bytes written
459 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000460int
Owen Taylor3473f882001-02-23 17:55:21 +0000461xmlFileRead (void * context, char * buffer, int len) {
462 return(fread(&buffer[0], 1, len, (FILE *) context));
463}
464
465/**
466 * xmlFileWrite:
467 * @context: the I/O context
468 * @buffer: where to drop data
469 * @len: number of bytes to write
470 *
471 * Write @len bytes from @buffer to the I/O channel.
472 *
473 * Returns the number of bytes written
474 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000475static int
Owen Taylor3473f882001-02-23 17:55:21 +0000476xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000477 int items;
478
479 items = fwrite(&buffer[0], len, 1, (FILE *) context);
480
481 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000482}
483
484/**
485 * xmlFileClose:
486 * @context: the I/O context
487 *
488 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000489 *
490 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000491 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000492int
Owen Taylor3473f882001-02-23 17:55:21 +0000493xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000494 FILE *fil;
495
496 fil = (FILE *) context;
497 if (fil == stdin)
498 return(0);
499 if (fil == stdout)
500 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000501 if (fil == stderr)
502 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000503 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000504}
505
506/**
507 * xmlFileFlush:
508 * @context: the I/O context
509 *
510 * Flush an I/O channel
511 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000512static int
Owen Taylor3473f882001-02-23 17:55:21 +0000513xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000514 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000515}
516
517#ifdef HAVE_ZLIB_H
518/************************************************************************
519 * *
520 * I/O for compressed file accesses *
521 * *
522 ************************************************************************/
523/**
524 * xmlGzfileMatch:
525 * @filename: the URI for matching
526 *
527 * input from compressed file test
528 *
529 * Returns 1 if matches, 0 otherwise
530 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000531static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000532xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000533 return(1);
534}
535
536/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000537 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000538 * @filename: the URI for matching
539 *
540 * input from compressed file open
541 * if @filename is " " then the standard input is used
542 *
543 * Returns an I/O context or NULL in case of error
544 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000545static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000546xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000547 const char *path = NULL;
548 gzFile fd;
549
550 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000551 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000552 return((void *) fd);
553 }
554
Daniel Veillardf4862f02002-09-10 11:13:43 +0000555 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
556#if defined (_WIN32) && !defined(__CYGWIN__)
557 path = &filename[17];
558#else
Owen Taylor3473f882001-02-23 17:55:21 +0000559 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000560#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000561 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000562#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000563 path = &filename[8];
564#else
Owen Taylor3473f882001-02-23 17:55:21 +0000565 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000566#endif
567 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000568 path = filename;
569
570 if (path == NULL)
571 return(NULL);
572 if (!xmlCheckFilename(path))
573 return(NULL);
574
575 fd = gzopen(path, "rb");
576 return((void *) fd);
577}
578
579/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000580 * xmlGzfileOpen:
581 * @filename: the URI for matching
582 *
583 * Wrapper around xmlGzfileOpen that try it with an unescaped
584 * version of @filename, if this fails fallback to @filename
585 */
586static void *
587xmlGzfileOpen (const char *filename) {
588 char *unescaped;
589 void *retval;
590 unescaped = xmlURIUnescapeString(filename, 0, NULL);
591 if (unescaped != NULL) {
592 retval = xmlGzfileOpen_real(unescaped);
593 } else {
594 retval = xmlGzfileOpen_real(filename);
595 }
596 xmlFree(unescaped);
597 return retval;
598}
599
600/**
Owen Taylor3473f882001-02-23 17:55:21 +0000601 * xmlGzfileOpenW:
602 * @filename: the URI for matching
603 * @compression: the compression factor (0 - 9 included)
604 *
605 * input from compressed file open
606 * if @filename is " " then the standard input is used
607 *
608 * Returns an I/O context or NULL in case of error
609 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000610static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000611xmlGzfileOpenW (const char *filename, int compression) {
612 const char *path = NULL;
613 char mode[15];
614 gzFile fd;
615
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000616 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000617 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000618 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000619 return((void *) fd);
620 }
621
Daniel Veillardf4862f02002-09-10 11:13:43 +0000622 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
623#if defined (_WIN32) && !defined(__CYGWIN__)
624 path = &filename[17];
625#else
Owen Taylor3473f882001-02-23 17:55:21 +0000626 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000627#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000628 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000629#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000630 path = &filename[8];
631#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000632 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000633#endif
634 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000635 path = filename;
636
637 if (path == NULL)
638 return(NULL);
639
640 fd = gzopen(path, mode);
641 return((void *) fd);
642}
643
644/**
645 * xmlGzfileRead:
646 * @context: the I/O context
647 * @buffer: where to drop data
648 * @len: number of bytes to write
649 *
650 * Read @len bytes to @buffer from the compressed I/O channel.
651 *
652 * Returns the number of bytes written
653 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000654static int
Owen Taylor3473f882001-02-23 17:55:21 +0000655xmlGzfileRead (void * context, char * buffer, int len) {
656 return(gzread((gzFile) context, &buffer[0], len));
657}
658
659/**
660 * xmlGzfileWrite:
661 * @context: the I/O context
662 * @buffer: where to drop data
663 * @len: number of bytes to write
664 *
665 * Write @len bytes from @buffer to the compressed I/O channel.
666 *
667 * Returns the number of bytes written
668 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000669static int
Owen Taylor3473f882001-02-23 17:55:21 +0000670xmlGzfileWrite (void * context, const char * buffer, int len) {
671 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
672}
673
674/**
675 * xmlGzfileClose:
676 * @context: the I/O context
677 *
678 * Close a compressed I/O channel
679 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000680static int
Owen Taylor3473f882001-02-23 17:55:21 +0000681xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000682 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000683}
684#endif /* HAVE_ZLIB_H */
685
686#ifdef LIBXML_HTTP_ENABLED
687/************************************************************************
688 * *
689 * I/O for HTTP file accesses *
690 * *
691 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000692
693typedef struct xmlIOHTTPWriteCtxt_
694{
695 int compression;
696
697 char * uri;
698
699 void * doc_buff;
700
701} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
702
703#ifdef HAVE_ZLIB_H
704
705#define DFLT_WBITS ( -15 )
706#define DFLT_MEM_LVL ( 8 )
707#define GZ_MAGIC1 ( 0x1f )
708#define GZ_MAGIC2 ( 0x8b )
709#define LXML_ZLIB_OS_CODE ( 0x03 )
710#define INIT_HTTP_BUFF_SIZE ( 32768 )
711#define DFLT_ZLIB_RATIO ( 5 )
712
713/*
714** Data structure and functions to work with sending compressed data
715** via HTTP.
716*/
717
718typedef struct xmlZMemBuff_
719{
720 unsigned long size;
721 unsigned long crc;
722
723 unsigned char * zbuff;
724 z_stream zctrl;
725
726} xmlZMemBuff, *xmlZMemBuffPtr;
727
728/**
729 * append_reverse_ulong
730 * @buff: Compressed memory buffer
731 * @data: Unsigned long to append
732 *
733 * Append a unsigned long in reverse byte order to the end of the
734 * memory buffer.
735 */
736static void
737append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
738
739 int idx;
740
741 if ( buff == NULL )
742 return;
743
744 /*
745 ** This is plagiarized from putLong in gzio.c (zlib source) where
746 ** the number "4" is hardcoded. If zlib is ever patched to
747 ** support 64 bit file sizes, this code would need to be patched
748 ** as well.
749 */
750
751 for ( idx = 0; idx < 4; idx++ ) {
752 *buff->zctrl.next_out = ( data & 0xff );
753 data >>= 8;
754 buff->zctrl.next_out++;
755 }
756
757 return;
758}
759
760/**
761 *
762 * xmlFreeZMemBuff
763 * @buff: The memory buffer context to clear
764 *
765 * Release all the resources associated with the compressed memory buffer.
766 */
767static void
768xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
769
770 int z_err;
771
772 if ( buff == NULL )
773 return;
774
775 xmlFree( buff->zbuff );
776 z_err = deflateEnd( &buff->zctrl );
777#ifdef DEBUG_HTTP
778 if ( z_err != Z_OK )
779 xmlGenericError( xmlGenericErrorContext,
780 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
781 z_err );
782#endif
783
784 xmlFree( buff );
785 return;
786}
787
788/**
789 * xmlCreateZMemBuff
790 *@compression: Compression value to use
791 *
792 * Create a memory buffer to hold the compressed XML document. The
793 * compressed document in memory will end up being identical to what
794 * would be created if gzopen/gzwrite/gzclose were being used to
795 * write the document to disk. The code for the header/trailer data to
796 * the compression is plagiarized from the zlib source files.
797 */
798static void *
799xmlCreateZMemBuff( int compression ) {
800
801 int z_err;
802 int hdr_lgth;
803 xmlZMemBuffPtr buff = NULL;
804
805 if ( ( compression < 1 ) || ( compression > 9 ) )
806 return ( NULL );
807
808 /* Create the control and data areas */
809
810 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
811 if ( buff == NULL ) {
812 xmlGenericError( xmlGenericErrorContext,
813 "xmlCreateZMemBuff: %s\n",
814 "Failure allocating buffer context." );
815 return ( NULL );
816 }
817
818 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
819 buff->size = INIT_HTTP_BUFF_SIZE;
820 buff->zbuff = xmlMalloc( buff->size );
821 if ( buff->zbuff == NULL ) {
822 xmlFreeZMemBuff( buff );
823 xmlGenericError( xmlGenericErrorContext,
824 "xmlCreateZMemBuff: %s\n",
825 "Failure allocating data buffer." );
826 return ( NULL );
827 }
828
829 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
830 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
831 if ( z_err != Z_OK ) {
832 xmlFreeZMemBuff( buff );
833 buff = NULL;
834 xmlGenericError( xmlGenericErrorContext,
835 "xmlCreateZMemBuff: %s %d\n",
836 "Error initializing compression context. ZLIB error:",
837 z_err );
838 return ( NULL );
839 }
840
841 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +0000842 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000843 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
844 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +0000845 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
846 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
847 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
848 buff->zctrl.avail_out = buff->size - hdr_lgth;
849
850 return ( buff );
851}
852
853/**
854 * xmlZMemBuffExtend
855 * @buff: Buffer used to compress and consolidate data.
856 * @ext_amt: Number of bytes to extend the buffer.
857 *
858 * Extend the internal buffer used to store the compressed data by the
859 * specified amount.
860 *
861 * Returns 0 on success or -1 on failure to extend the buffer. On failure
862 * the original buffer still exists at the original size.
863 */
864static int
865xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
866
867 int rc = -1;
868 size_t new_size;
869 size_t cur_used;
870
871 unsigned char * tmp_ptr = NULL;
872
873 if ( buff == NULL )
874 return ( -1 );
875
876 else if ( ext_amt == 0 )
877 return ( 0 );
878
879 cur_used = buff->zctrl.next_out - buff->zbuff;
880 new_size = buff->size + ext_amt;
881
882#ifdef DEBUG_HTTP
883 if ( cur_used > new_size )
884 xmlGenericError( xmlGenericErrorContext,
885 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
886 "Buffer overwrite detected during compressed memory",
887 "buffer extension. Overflowed by",
888 (cur_used - new_size ) );
889#endif
890
891 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
892 if ( tmp_ptr != NULL ) {
893 rc = 0;
894 buff->size = new_size;
895 buff->zbuff = tmp_ptr;
896 buff->zctrl.next_out = tmp_ptr + cur_used;
897 buff->zctrl.avail_out = new_size - cur_used;
898 }
899 else {
900 xmlGenericError( xmlGenericErrorContext,
901 "xmlZMemBuffExtend: %s %lu bytes.\n",
902 "Allocation failure extending output buffer to",
903 new_size );
904 }
905
906 return ( rc );
907}
908
909/**
910 * xmlZMemBuffAppend
911 * @buff: Buffer used to compress and consolidate data
912 * @src: Uncompressed source content to append to buffer
913 * @len: Length of source data to append to buffer
914 *
915 * Compress and append data to the internal buffer. The data buffer
916 * will be expanded if needed to store the additional data.
917 *
918 * Returns the number of bytes appended to the buffer or -1 on error.
919 */
920static int
921xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
922
923 int z_err;
924 size_t min_accept;
925
926 if ( ( buff == NULL ) || ( src == NULL ) )
927 return ( -1 );
928
929 buff->zctrl.avail_in = len;
930 buff->zctrl.next_in = (unsigned char *)src;
931 while ( buff->zctrl.avail_in > 0 ) {
932 /*
933 ** Extend the buffer prior to deflate call if a reasonable amount
934 ** of output buffer space is not available.
935 */
936 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
937 if ( buff->zctrl.avail_out <= min_accept ) {
938 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
939 return ( -1 );
940 }
941
942 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
943 if ( z_err != Z_OK ) {
944 xmlGenericError( xmlGenericErrorContext,
945 "xmlZMemBuffAppend: %s %d %s - %d",
946 "Compression error while appending",
947 len, "bytes to buffer. ZLIB error", z_err );
948 return ( -1 );
949 }
950 }
951
952 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
953
954 return ( len );
955}
956
957/**
958 * xmlZMemBuffGetContent
959 * @buff: Compressed memory content buffer
960 * @data_ref: Pointer reference to point to compressed content
961 *
962 * Flushes the compression buffers, appends gzip file trailers and
963 * returns the compressed content and length of the compressed data.
964 * NOTE: The gzip trailer code here is plagiarized from zlib source.
965 *
966 * Returns the length of the compressed data or -1 on error.
967 */
968static int
969xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
970
971 int zlgth = -1;
972 int z_err;
973
974 if ( ( buff == NULL ) || ( data_ref == NULL ) )
975 return ( -1 );
976
977 /* Need to loop until compression output buffers are flushed */
978
979 do
980 {
981 z_err = deflate( &buff->zctrl, Z_FINISH );
982 if ( z_err == Z_OK ) {
983 /* In this case Z_OK means more buffer space needed */
984
985 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
986 return ( -1 );
987 }
988 }
989 while ( z_err == Z_OK );
990
991 /* If the compression state is not Z_STREAM_END, some error occurred */
992
993 if ( z_err == Z_STREAM_END ) {
994
995 /* Need to append the gzip data trailer */
996
997 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
998 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
999 return ( -1 );
1000 }
1001
1002 /*
1003 ** For whatever reason, the CRC and length data are pushed out
1004 ** in reverse byte order. So a memcpy can't be used here.
1005 */
1006
1007 append_reverse_ulong( buff, buff->crc );
1008 append_reverse_ulong( buff, buff->zctrl.total_in );
1009
1010 zlgth = buff->zctrl.next_out - buff->zbuff;
1011 *data_ref = (char *)buff->zbuff;
1012 }
1013
1014 else
1015 xmlGenericError( xmlGenericErrorContext,
1016 "xmlZMemBuffGetContent: %s - %d\n",
1017 "Error flushing zlib buffers. Error code", z_err );
1018
1019 return ( zlgth );
1020}
1021#endif /* HAVE_ZLIB_H */
1022
1023/**
1024 * xmlFreeHTTPWriteCtxt
1025 * @ctxt: Context to cleanup
1026 *
1027 * Free allocated memory and reclaim system resources.
1028 *
1029 * No return value.
1030 */
1031static void
1032xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1033{
1034 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001035 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001036
1037 if ( ctxt->doc_buff != NULL ) {
1038
1039#ifdef HAVE_ZLIB_H
1040 if ( ctxt->compression > 0 ) {
1041 xmlFreeZMemBuff( ctxt->doc_buff );
1042 }
1043 else
1044#endif
1045 {
1046 xmlOutputBufferClose( ctxt->doc_buff );
1047 }
1048 }
1049
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001050 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001051 return;
1052}
1053
1054
Owen Taylor3473f882001-02-23 17:55:21 +00001055/**
1056 * xmlIOHTTPMatch:
1057 * @filename: the URI for matching
1058 *
1059 * check if the URI matches an HTTP one
1060 *
1061 * Returns 1 if matches, 0 otherwise
1062 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001063int
Owen Taylor3473f882001-02-23 17:55:21 +00001064xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001065 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001066 return(1);
1067 return(0);
1068}
1069
1070/**
1071 * xmlIOHTTPOpen:
1072 * @filename: the URI for matching
1073 *
1074 * open an HTTP I/O channel
1075 *
1076 * Returns an I/O context or NULL in case of error
1077 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001078void *
Owen Taylor3473f882001-02-23 17:55:21 +00001079xmlIOHTTPOpen (const char *filename) {
1080 return(xmlNanoHTTPOpen(filename, NULL));
1081}
1082
1083/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001084 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001085 * @post_uri: The destination URI for the document
1086 * @compression: The compression desired for the document.
1087 *
1088 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1089 * request. Non-static as is called from the output buffer creation routine.
1090 *
1091 * Returns an I/O context or NULL in case of error.
1092 */
1093
1094void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001095xmlIOHTTPOpenW(const char *post_uri, int compression)
1096{
Daniel Veillardf012a642001-07-23 19:10:52 +00001097
Daniel Veillard572577e2002-01-18 16:23:55 +00001098 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001099
Daniel Veillard572577e2002-01-18 16:23:55 +00001100 if (post_uri == NULL)
1101 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001102
Daniel Veillard572577e2002-01-18 16:23:55 +00001103 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1104 if (ctxt == NULL) {
1105 xmlGenericError(xmlGenericErrorContext,
1106 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
1107 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001108 }
1109
Daniel Veillard572577e2002-01-18 16:23:55 +00001110 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001111
Daniel Veillard572577e2002-01-18 16:23:55 +00001112 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1113 if (ctxt->uri == NULL) {
1114 xmlGenericError(xmlGenericErrorContext,
1115 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
1116 xmlFreeHTTPWriteCtxt(ctxt);
1117 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001118 }
1119
1120 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001121 * ** Since the document length is required for an HTTP post,
1122 * ** need to put the document into a buffer. A memory buffer
1123 * ** is being used to avoid pushing the data to disk and back.
1124 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001125
1126#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001127 if ((compression > 0) && (compression <= 9)) {
1128
1129 ctxt->compression = compression;
1130 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1131 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001132#endif
1133 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001134 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001135
Daniel Veillard572577e2002-01-18 16:23:55 +00001136 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001137 }
1138
Daniel Veillard572577e2002-01-18 16:23:55 +00001139 if (ctxt->doc_buff == NULL) {
1140 xmlFreeHTTPWriteCtxt(ctxt);
1141 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001142 }
1143
Daniel Veillard572577e2002-01-18 16:23:55 +00001144 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001145}
1146
1147/**
1148 * xmlIOHTTPDfltOpenW
1149 * @post_uri: The destination URI for this document.
1150 *
1151 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1152 * HTTP post command. This function should generally not be used as
1153 * the open callback is short circuited in xmlOutputBufferCreateFile.
1154 *
1155 * Returns a pointer to the new IO context.
1156 */
1157static void *
1158xmlIOHTTPDfltOpenW( const char * post_uri ) {
1159 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1160}
1161
1162/**
Owen Taylor3473f882001-02-23 17:55:21 +00001163 * xmlIOHTTPRead:
1164 * @context: the I/O context
1165 * @buffer: where to drop data
1166 * @len: number of bytes to write
1167 *
1168 * Read @len bytes to @buffer from the I/O channel.
1169 *
1170 * Returns the number of bytes written
1171 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001172int
Owen Taylor3473f882001-02-23 17:55:21 +00001173xmlIOHTTPRead(void * context, char * buffer, int len) {
1174 return(xmlNanoHTTPRead(context, &buffer[0], len));
1175}
1176
1177/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001178 * xmlIOHTTPWrite
1179 * @context: previously opened writing context
1180 * @buffer: data to output to temporary buffer
1181 * @len: bytes to output
1182 *
1183 * Collect data from memory buffer into a temporary file for later
1184 * processing.
1185 *
1186 * Returns number of bytes written.
1187 */
1188
1189static int
1190xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1191
1192 xmlIOHTTPWriteCtxtPtr ctxt = context;
1193
1194 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1195 return ( -1 );
1196
1197 if ( len > 0 ) {
1198
1199 /* Use gzwrite or fwrite as previously setup in the open call */
1200
1201#ifdef HAVE_ZLIB_H
1202 if ( ctxt->compression > 0 )
1203 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1204
1205 else
1206#endif
1207 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1208
1209 if ( len < 0 ) {
1210 xmlGenericError( xmlGenericErrorContext,
1211 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1212 "Error appending to internal buffer.",
1213 "Error sending document to URI",
1214 ctxt->uri );
1215 }
1216 }
1217
1218 return ( len );
1219}
1220
1221
1222/**
Owen Taylor3473f882001-02-23 17:55:21 +00001223 * xmlIOHTTPClose:
1224 * @context: the I/O context
1225 *
1226 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001227 *
1228 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001229 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001230int
Owen Taylor3473f882001-02-23 17:55:21 +00001231xmlIOHTTPClose (void * context) {
1232 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001233 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001234}
Daniel Veillardf012a642001-07-23 19:10:52 +00001235
1236/**
1237 * xmlIOHTTCloseWrite
1238 * @context: The I/O context
1239 * @http_mthd: The HTTP method to be used when sending the data
1240 *
1241 * Close the transmit HTTP I/O channel and actually send the data.
1242 */
1243static int
1244xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1245
1246 int close_rc = -1;
1247 int http_rtn = 0;
1248 int content_lgth = 0;
1249 xmlIOHTTPWriteCtxtPtr ctxt = context;
1250
1251 char * http_content = NULL;
1252 char * content_encoding = NULL;
1253 char * content_type = (char *) "text/xml";
1254 void * http_ctxt = NULL;
1255
1256 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1257 return ( -1 );
1258
1259 /* Retrieve the content from the appropriate buffer */
1260
1261#ifdef HAVE_ZLIB_H
1262
1263 if ( ctxt->compression > 0 ) {
1264 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1265 content_encoding = (char *) "Content-Encoding: gzip";
1266 }
1267 else
1268#endif
1269 {
1270 /* Pull the data out of the memory output buffer */
1271
1272 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1273 http_content = (char *)dctxt->buffer->content;
1274 content_lgth = dctxt->buffer->use;
1275 }
1276
1277 if ( http_content == NULL ) {
1278 xmlGenericError( xmlGenericErrorContext,
1279 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1280 "Error retrieving content.\nUnable to",
1281 http_mthd, "data to URI", ctxt->uri );
1282 }
1283
1284 else {
1285
1286 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1287 &content_type, content_encoding,
1288 content_lgth );
1289
1290 if ( http_ctxt != NULL ) {
1291#ifdef DEBUG_HTTP
1292 /* If testing/debugging - dump reply with request content */
1293
1294 FILE * tst_file = NULL;
1295 char buffer[ 4096 ];
1296 char * dump_name = NULL;
1297 int avail;
1298
1299 xmlGenericError( xmlGenericErrorContext,
1300 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1301 http_mthd, ctxt->uri,
1302 xmlNanoHTTPReturnCode( http_ctxt ) );
1303
1304 /*
1305 ** Since either content or reply may be gzipped,
1306 ** dump them to separate files instead of the
1307 ** standard error context.
1308 */
1309
1310 dump_name = tempnam( NULL, "lxml" );
1311 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001312 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001313
1314 tst_file = fopen( buffer, "w" );
1315 if ( tst_file != NULL ) {
1316 xmlGenericError( xmlGenericErrorContext,
1317 "Transmitted content saved in file: %s\n", buffer );
1318
1319 fwrite( http_content, sizeof( char ),
1320 content_lgth, tst_file );
1321 fclose( tst_file );
1322 }
1323
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001324 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001325 tst_file = fopen( buffer, "w" );
1326 if ( tst_file != NULL ) {
1327 xmlGenericError( xmlGenericErrorContext,
1328 "Reply content saved in file: %s\n", buffer );
1329
1330
1331 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1332 buffer, sizeof( buffer ) )) > 0 ) {
1333
1334 fwrite( buffer, sizeof( char ), avail, tst_file );
1335 }
1336
1337 fclose( tst_file );
1338 }
1339
1340 free( dump_name );
1341 }
1342#endif /* DEBUG_HTTP */
1343
1344 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1345 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1346 close_rc = 0;
1347 else
1348 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001349 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001350 http_mthd, content_lgth,
1351 "bytes to URI", ctxt->uri,
1352 "failed. HTTP return code:", http_rtn );
1353
1354 xmlNanoHTTPClose( http_ctxt );
1355 xmlFree( content_type );
1356 }
1357 }
1358
1359 /* Final cleanups */
1360
1361 xmlFreeHTTPWriteCtxt( ctxt );
1362
1363 return ( close_rc );
1364}
1365
1366/**
1367 * xmlIOHTTPClosePut
1368 *
1369 * @context: The I/O context
1370 *
1371 * Close the transmit HTTP I/O channel and actually send data using a PUT
1372 * HTTP method.
1373 */
1374static int
1375xmlIOHTTPClosePut( void * ctxt ) {
1376 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1377}
1378
1379
1380/**
1381 * xmlIOHTTPClosePost
1382 *
1383 * @context: The I/O context
1384 *
1385 * Close the transmit HTTP I/O channel and actually send data using a POST
1386 * HTTP method.
1387 */
1388static int
1389xmlIOHTTPClosePost( void * ctxt ) {
1390 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1391}
1392
Owen Taylor3473f882001-02-23 17:55:21 +00001393#endif /* LIBXML_HTTP_ENABLED */
1394
1395#ifdef LIBXML_FTP_ENABLED
1396/************************************************************************
1397 * *
1398 * I/O for FTP file accesses *
1399 * *
1400 ************************************************************************/
1401/**
1402 * xmlIOFTPMatch:
1403 * @filename: the URI for matching
1404 *
1405 * check if the URI matches an FTP one
1406 *
1407 * Returns 1 if matches, 0 otherwise
1408 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001409int
Owen Taylor3473f882001-02-23 17:55:21 +00001410xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001411 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001412 return(1);
1413 return(0);
1414}
1415
1416/**
1417 * xmlIOFTPOpen:
1418 * @filename: the URI for matching
1419 *
1420 * open an FTP I/O channel
1421 *
1422 * Returns an I/O context or NULL in case of error
1423 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001424void *
Owen Taylor3473f882001-02-23 17:55:21 +00001425xmlIOFTPOpen (const char *filename) {
1426 return(xmlNanoFTPOpen(filename));
1427}
1428
1429/**
1430 * xmlIOFTPRead:
1431 * @context: the I/O context
1432 * @buffer: where to drop data
1433 * @len: number of bytes to write
1434 *
1435 * Read @len bytes to @buffer from the I/O channel.
1436 *
1437 * Returns the number of bytes written
1438 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001439int
Owen Taylor3473f882001-02-23 17:55:21 +00001440xmlIOFTPRead(void * context, char * buffer, int len) {
1441 return(xmlNanoFTPRead(context, &buffer[0], len));
1442}
1443
1444/**
1445 * xmlIOFTPClose:
1446 * @context: the I/O context
1447 *
1448 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001449 *
1450 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001451 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001452int
Owen Taylor3473f882001-02-23 17:55:21 +00001453xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001454 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001455}
1456#endif /* LIBXML_FTP_ENABLED */
1457
1458
1459/**
1460 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001461 * @matchFunc: the xmlInputMatchCallback
1462 * @openFunc: the xmlInputOpenCallback
1463 * @readFunc: the xmlInputReadCallback
1464 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001465 *
1466 * Register a new set of I/O callback for handling parser input.
1467 *
1468 * Returns the registered handler number or -1 in case of error
1469 */
1470int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001471xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1472 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1473 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001474 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1475 return(-1);
1476 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001477 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1478 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1479 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1480 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001481 return(xmlInputCallbackNr++);
1482}
1483
1484/**
1485 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001486 * @matchFunc: the xmlOutputMatchCallback
1487 * @openFunc: the xmlOutputOpenCallback
1488 * @writeFunc: the xmlOutputWriteCallback
1489 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001490 *
1491 * Register a new set of I/O callback for handling output.
1492 *
1493 * Returns the registered handler number or -1 in case of error
1494 */
1495int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001496xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1497 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1498 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001499 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1500 return(-1);
1501 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001502 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1503 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1504 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1505 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001506 return(xmlOutputCallbackNr++);
1507}
1508
1509/**
1510 * xmlRegisterDefaultInputCallbacks:
1511 *
1512 * Registers the default compiled-in I/O handlers.
1513 */
1514void
Owen Taylor3473f882001-02-23 17:55:21 +00001515xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001516(void) {
1517 if (xmlInputCallbackInitialized)
1518 return;
1519
1520 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1521 xmlFileRead, xmlFileClose);
1522#ifdef HAVE_ZLIB_H
1523 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1524 xmlGzfileRead, xmlGzfileClose);
1525#endif /* HAVE_ZLIB_H */
1526
1527#ifdef LIBXML_HTTP_ENABLED
1528 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1529 xmlIOHTTPRead, xmlIOHTTPClose);
1530#endif /* LIBXML_HTTP_ENABLED */
1531
1532#ifdef LIBXML_FTP_ENABLED
1533 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1534 xmlIOFTPRead, xmlIOFTPClose);
1535#endif /* LIBXML_FTP_ENABLED */
1536 xmlInputCallbackInitialized = 1;
1537}
1538
1539/**
1540 * xmlRegisterDefaultOutputCallbacks:
1541 *
1542 * Registers the default compiled-in I/O handlers.
1543 */
1544void
Owen Taylor3473f882001-02-23 17:55:21 +00001545xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001546(void) {
1547 if (xmlOutputCallbackInitialized)
1548 return;
1549
1550 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1551 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001552
1553#ifdef LIBXML_HTTP_ENABLED
1554 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1555 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1556#endif
1557
Owen Taylor3473f882001-02-23 17:55:21 +00001558/*********************************
1559 No way a-priori to distinguish between gzipped files from
1560 uncompressed ones except opening if existing then closing
1561 and saving with same compression ratio ... a pain.
1562
1563#ifdef HAVE_ZLIB_H
1564 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1565 xmlGzfileWrite, xmlGzfileClose);
1566#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001567
1568 Nor FTP PUT ....
1569#ifdef LIBXML_FTP_ENABLED
1570 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1571 xmlIOFTPWrite, xmlIOFTPClose);
1572#endif
1573 **********************************/
1574 xmlOutputCallbackInitialized = 1;
1575}
1576
Daniel Veillardf012a642001-07-23 19:10:52 +00001577#ifdef LIBXML_HTTP_ENABLED
1578/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001579 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001580 *
1581 * By default, libxml submits HTTP output requests using the "PUT" method.
1582 * Calling this method changes the HTTP output method to use the "POST"
1583 * method instead.
1584 *
1585 */
1586void
1587xmlRegisterHTTPPostCallbacks( void ) {
1588
1589 /* Register defaults if not done previously */
1590
1591 if ( xmlOutputCallbackInitialized == 0 )
1592 xmlRegisterDefaultOutputCallbacks( );
1593
1594 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1595 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1596 return;
1597}
1598#endif
1599
Owen Taylor3473f882001-02-23 17:55:21 +00001600/**
1601 * xmlAllocParserInputBuffer:
1602 * @enc: the charset encoding if known
1603 *
1604 * Create a buffered parser input for progressive parsing
1605 *
1606 * Returns the new parser input or NULL
1607 */
1608xmlParserInputBufferPtr
1609xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1610 xmlParserInputBufferPtr ret;
1611
1612 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1613 if (ret == NULL) {
1614 xmlGenericError(xmlGenericErrorContext,
1615 "xmlAllocParserInputBuffer : out of memory!\n");
1616 return(NULL);
1617 }
1618 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1619 ret->buffer = xmlBufferCreate();
1620 if (ret->buffer == NULL) {
1621 xmlFree(ret);
1622 return(NULL);
1623 }
1624 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1625 ret->encoder = xmlGetCharEncodingHandler(enc);
1626 if (ret->encoder != NULL)
1627 ret->raw = xmlBufferCreate();
1628 else
1629 ret->raw = NULL;
1630 ret->readcallback = NULL;
1631 ret->closecallback = NULL;
1632 ret->context = NULL;
1633
1634 return(ret);
1635}
1636
1637/**
1638 * xmlAllocOutputBuffer:
1639 * @encoder: the encoding converter or NULL
1640 *
1641 * Create a buffered parser output
1642 *
1643 * Returns the new parser output or NULL
1644 */
1645xmlOutputBufferPtr
1646xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1647 xmlOutputBufferPtr ret;
1648
1649 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1650 if (ret == NULL) {
1651 xmlGenericError(xmlGenericErrorContext,
1652 "xmlAllocOutputBuffer : out of memory!\n");
1653 return(NULL);
1654 }
1655 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1656 ret->buffer = xmlBufferCreate();
1657 if (ret->buffer == NULL) {
1658 xmlFree(ret);
1659 return(NULL);
1660 }
1661 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1662 ret->encoder = encoder;
1663 if (encoder != NULL) {
1664 ret->conv = xmlBufferCreateSize(4000);
1665 /*
1666 * This call is designed to initiate the encoder state
1667 */
1668 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1669 } else
1670 ret->conv = NULL;
1671 ret->writecallback = NULL;
1672 ret->closecallback = NULL;
1673 ret->context = NULL;
1674 ret->written = 0;
1675
1676 return(ret);
1677}
1678
1679/**
1680 * xmlFreeParserInputBuffer:
1681 * @in: a buffered parser input
1682 *
1683 * Free up the memory used by a buffered parser input
1684 */
1685void
1686xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1687 if (in->raw) {
1688 xmlBufferFree(in->raw);
1689 in->raw = NULL;
1690 }
1691 if (in->encoder != NULL) {
1692 xmlCharEncCloseFunc(in->encoder);
1693 }
1694 if (in->closecallback != NULL) {
1695 in->closecallback(in->context);
1696 }
1697 if (in->buffer != NULL) {
1698 xmlBufferFree(in->buffer);
1699 in->buffer = NULL;
1700 }
1701
Owen Taylor3473f882001-02-23 17:55:21 +00001702 xmlFree(in);
1703}
1704
1705/**
1706 * xmlOutputBufferClose:
1707 * @out: a buffered output
1708 *
1709 * flushes and close the output I/O channel
1710 * and free up all the associated resources
1711 *
1712 * Returns the number of byte written or -1 in case of error.
1713 */
1714int
1715xmlOutputBufferClose(xmlOutputBufferPtr out) {
1716 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001717 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001718
1719 if (out == NULL)
1720 return(-1);
1721 if (out->writecallback != NULL)
1722 xmlOutputBufferFlush(out);
1723 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001724 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001725 }
1726 written = out->written;
1727 if (out->conv) {
1728 xmlBufferFree(out->conv);
1729 out->conv = NULL;
1730 }
1731 if (out->encoder != NULL) {
1732 xmlCharEncCloseFunc(out->encoder);
1733 }
1734 if (out->buffer != NULL) {
1735 xmlBufferFree(out->buffer);
1736 out->buffer = NULL;
1737 }
1738
Owen Taylor3473f882001-02-23 17:55:21 +00001739 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001740 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001741}
1742
1743/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001744 * xmlParserInputBufferCreateFname:
1745 * @URI: a C string containing the URI or filename
1746 * @enc: the charset encoding if known
1747 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001748 * Returns the new parser input or NULL
1749 */
1750/**
Owen Taylor3473f882001-02-23 17:55:21 +00001751 * xmlParserInputBufferCreateFilename:
1752 * @URI: a C string containing the URI or filename
1753 * @enc: the charset encoding if known
1754 *
1755 * Create a buffered parser input for the progressive parsing of a file
1756 * If filename is "-' then we use stdin as the input.
1757 * Automatic support for ZLIB/Compress compressed document is provided
1758 * by default if found at compile-time.
1759 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1760 *
1761 * Returns the new parser input or NULL
1762 */
1763xmlParserInputBufferPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001764xmlParserInputBufferCreateFilename
Owen Taylor3473f882001-02-23 17:55:21 +00001765(const char *URI, xmlCharEncoding enc) {
1766 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001767 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001768 void *context = NULL;
Daniel Veillardf4862f02002-09-10 11:13:43 +00001769 char *normalized;
Owen Taylor3473f882001-02-23 17:55:21 +00001770
1771 if (xmlInputCallbackInitialized == 0)
1772 xmlRegisterDefaultInputCallbacks();
1773
1774 if (URI == NULL) return(NULL);
Daniel Veillardf4862f02002-09-10 11:13:43 +00001775 normalized = (char *) xmlNormalizeWindowsPath((const xmlChar *)URI);
1776 if (normalized == NULL) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001777
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001778#ifdef LIBXML_CATALOG_ENABLED
1779#endif
1780
Owen Taylor3473f882001-02-23 17:55:21 +00001781 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001782 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001783 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001784 */
1785 if (context == NULL) {
1786 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1787 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1788 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardf4862f02002-09-10 11:13:43 +00001789 context = xmlInputCallbackTable[i].opencallback(normalized);
Daniel Veillard388236f2001-07-08 18:35:48 +00001790 if (context != NULL)
1791 break;
1792 }
Owen Taylor3473f882001-02-23 17:55:21 +00001793 }
1794 }
Daniel Veillardf4862f02002-09-10 11:13:43 +00001795 xmlFree(normalized);
Owen Taylor3473f882001-02-23 17:55:21 +00001796 if (context == NULL) {
1797 return(NULL);
1798 }
1799
1800 /*
1801 * Allocate the Input buffer front-end.
1802 */
1803 ret = xmlAllocParserInputBuffer(enc);
1804 if (ret != NULL) {
1805 ret->context = context;
1806 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1807 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1808 }
1809 return(ret);
1810}
1811
1812/**
1813 * xmlOutputBufferCreateFilename:
1814 * @URI: a C string containing the URI or filename
1815 * @encoder: the encoding converter or NULL
1816 * @compression: the compression ration (0 none, 9 max).
1817 *
1818 * Create a buffered output for the progressive saving of a file
1819 * If filename is "-' then we use stdout as the output.
1820 * Automatic support for ZLIB/Compress compressed document is provided
1821 * by default if found at compile-time.
1822 * TODO: currently if compression is set, the library only support
1823 * writing to a local file.
1824 *
1825 * Returns the new output or NULL
1826 */
1827xmlOutputBufferPtr
1828xmlOutputBufferCreateFilename(const char *URI,
1829 xmlCharEncodingHandlerPtr encoder,
1830 int compression) {
1831 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001832 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001833 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001834 char *unescaped;
Daniel Veillardf4862f02002-09-10 11:13:43 +00001835 char *normalized;
Owen Taylor3473f882001-02-23 17:55:21 +00001836
Daniel Veillardf012a642001-07-23 19:10:52 +00001837 int is_http_uri = 0; /* Can't change if HTTP disabled */
1838
Owen Taylor3473f882001-02-23 17:55:21 +00001839 if (xmlOutputCallbackInitialized == 0)
1840 xmlRegisterDefaultOutputCallbacks();
1841
1842 if (URI == NULL) return(NULL);
Daniel Veillardf4862f02002-09-10 11:13:43 +00001843 normalized = (char *) xmlNormalizeWindowsPath((const xmlChar *)URI);
1844 if (normalized == NULL) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001845
Daniel Veillardf012a642001-07-23 19:10:52 +00001846#ifdef LIBXML_HTTP_ENABLED
1847 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1848
Daniel Veillardf4862f02002-09-10 11:13:43 +00001849 is_http_uri = xmlIOHTTPMatch( normalized );
Daniel Veillardf012a642001-07-23 19:10:52 +00001850#endif
1851
Owen Taylor3473f882001-02-23 17:55:21 +00001852
1853 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001854 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001855 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001856 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001857 */
Daniel Veillardf4862f02002-09-10 11:13:43 +00001858 unescaped = xmlURIUnescapeString(normalized, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001859 if (unescaped != NULL) {
1860#ifdef HAVE_ZLIB_H
1861 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1862 context = xmlGzfileOpenW(unescaped, compression);
1863 if (context != NULL) {
1864 ret = xmlAllocOutputBuffer(encoder);
1865 if (ret != NULL) {
1866 ret->context = context;
1867 ret->writecallback = xmlGzfileWrite;
1868 ret->closecallback = xmlGzfileClose;
1869 }
1870 xmlFree(unescaped);
Daniel Veillardf4862f02002-09-10 11:13:43 +00001871 xmlFree(normalized);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001872 return(ret);
1873 }
1874 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001875#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001876 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1877 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1878 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1879#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1880 /* Need to pass compression parameter into HTTP open calls */
1881 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1882 context = xmlIOHTTPOpenW(unescaped, compression);
1883 else
1884#endif
1885 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1886 if (context != NULL)
1887 break;
1888 }
1889 }
1890 xmlFree(unescaped);
1891 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001892
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001893 /*
1894 * If this failed try with a non-escaped URI this may be a strange
1895 * filename
1896 */
1897 if (context == NULL) {
1898#ifdef HAVE_ZLIB_H
1899 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Daniel Veillardf4862f02002-09-10 11:13:43 +00001900 context = xmlGzfileOpenW(normalized, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001901 if (context != NULL) {
1902 ret = xmlAllocOutputBuffer(encoder);
1903 if (ret != NULL) {
1904 ret->context = context;
1905 ret->writecallback = xmlGzfileWrite;
1906 ret->closecallback = xmlGzfileClose;
1907 }
Daniel Veillardf4862f02002-09-10 11:13:43 +00001908 xmlFree(normalized);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001909 return(ret);
1910 }
1911 }
1912#endif
1913 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1914 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Daniel Veillardf4862f02002-09-10 11:13:43 +00001915 (xmlOutputCallbackTable[i].matchcallback(normalized) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001916#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1917 /* Need to pass compression parameter into HTTP open calls */
1918 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1919 context = xmlIOHTTPOpenW(URI, compression);
1920 else
1921#endif
1922 context = xmlOutputCallbackTable[i].opencallback(URI);
1923 if (context != NULL)
1924 break;
1925 }
Owen Taylor3473f882001-02-23 17:55:21 +00001926 }
1927 }
Daniel Veillardf4862f02002-09-10 11:13:43 +00001928 xmlFree(normalized);
Daniel Veillardf012a642001-07-23 19:10:52 +00001929
Owen Taylor3473f882001-02-23 17:55:21 +00001930 if (context == NULL) {
1931 return(NULL);
1932 }
1933
1934 /*
1935 * Allocate the Output buffer front-end.
1936 */
1937 ret = xmlAllocOutputBuffer(encoder);
1938 if (ret != NULL) {
1939 ret->context = context;
1940 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1941 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1942 }
1943 return(ret);
1944}
1945
1946/**
1947 * xmlParserInputBufferCreateFile:
1948 * @file: a FILE*
1949 * @enc: the charset encoding if known
1950 *
1951 * Create a buffered parser input for the progressive parsing of a FILE *
1952 * buffered C I/O
1953 *
1954 * Returns the new parser input or NULL
1955 */
1956xmlParserInputBufferPtr
1957xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1958 xmlParserInputBufferPtr ret;
1959
1960 if (xmlInputCallbackInitialized == 0)
1961 xmlRegisterDefaultInputCallbacks();
1962
1963 if (file == NULL) return(NULL);
1964
1965 ret = xmlAllocParserInputBuffer(enc);
1966 if (ret != NULL) {
1967 ret->context = file;
1968 ret->readcallback = xmlFileRead;
1969 ret->closecallback = xmlFileFlush;
1970 }
1971
1972 return(ret);
1973}
1974
1975/**
1976 * xmlOutputBufferCreateFile:
1977 * @file: a FILE*
1978 * @encoder: the encoding converter or NULL
1979 *
1980 * Create a buffered output for the progressive saving to a FILE *
1981 * buffered C I/O
1982 *
1983 * Returns the new parser output or NULL
1984 */
1985xmlOutputBufferPtr
1986xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1987 xmlOutputBufferPtr ret;
1988
1989 if (xmlOutputCallbackInitialized == 0)
1990 xmlRegisterDefaultOutputCallbacks();
1991
1992 if (file == NULL) return(NULL);
1993
1994 ret = xmlAllocOutputBuffer(encoder);
1995 if (ret != NULL) {
1996 ret->context = file;
1997 ret->writecallback = xmlFileWrite;
1998 ret->closecallback = xmlFileFlush;
1999 }
2000
2001 return(ret);
2002}
2003
2004/**
2005 * xmlParserInputBufferCreateFd:
2006 * @fd: a file descriptor number
2007 * @enc: the charset encoding if known
2008 *
2009 * Create a buffered parser input for the progressive parsing for the input
2010 * from a file descriptor
2011 *
2012 * Returns the new parser input or NULL
2013 */
2014xmlParserInputBufferPtr
2015xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2016 xmlParserInputBufferPtr ret;
2017
2018 if (fd < 0) return(NULL);
2019
2020 ret = xmlAllocParserInputBuffer(enc);
2021 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002022 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002023 ret->readcallback = xmlFdRead;
2024 ret->closecallback = xmlFdClose;
2025 }
2026
2027 return(ret);
2028}
2029
2030/**
2031 * xmlParserInputBufferCreateMem:
2032 * @mem: the memory input
2033 * @size: the length of the memory block
2034 * @enc: the charset encoding if known
2035 *
2036 * Create a buffered parser input for the progressive parsing for the input
2037 * from a memory area.
2038 *
2039 * Returns the new parser input or NULL
2040 */
2041xmlParserInputBufferPtr
2042xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2043 xmlParserInputBufferPtr ret;
2044
2045 if (size <= 0) return(NULL);
2046 if (mem == NULL) return(NULL);
2047
2048 ret = xmlAllocParserInputBuffer(enc);
2049 if (ret != NULL) {
2050 ret->context = (void *) mem;
2051 ret->readcallback = (xmlInputReadCallback) xmlNop;
2052 ret->closecallback = NULL;
2053 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2054 }
2055
2056 return(ret);
2057}
2058
2059/**
2060 * xmlOutputBufferCreateFd:
2061 * @fd: a file descriptor number
2062 * @encoder: the encoding converter or NULL
2063 *
2064 * Create a buffered output for the progressive saving
2065 * to a file descriptor
2066 *
2067 * Returns the new parser output or NULL
2068 */
2069xmlOutputBufferPtr
2070xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2071 xmlOutputBufferPtr ret;
2072
2073 if (fd < 0) return(NULL);
2074
2075 ret = xmlAllocOutputBuffer(encoder);
2076 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002077 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002078 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002079 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002080 }
2081
2082 return(ret);
2083}
2084
2085/**
2086 * xmlParserInputBufferCreateIO:
2087 * @ioread: an I/O read function
2088 * @ioclose: an I/O close function
2089 * @ioctx: an I/O handler
2090 * @enc: the charset encoding if known
2091 *
2092 * Create a buffered parser input for the progressive parsing for the input
2093 * from an I/O handler
2094 *
2095 * Returns the new parser input or NULL
2096 */
2097xmlParserInputBufferPtr
2098xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2099 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2100 xmlParserInputBufferPtr ret;
2101
2102 if (ioread == NULL) return(NULL);
2103
2104 ret = xmlAllocParserInputBuffer(enc);
2105 if (ret != NULL) {
2106 ret->context = (void *) ioctx;
2107 ret->readcallback = ioread;
2108 ret->closecallback = ioclose;
2109 }
2110
2111 return(ret);
2112}
2113
2114/**
2115 * xmlOutputBufferCreateIO:
2116 * @iowrite: an I/O write function
2117 * @ioclose: an I/O close function
2118 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002119 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002120 *
2121 * Create a buffered output for the progressive saving
2122 * to an I/O handler
2123 *
2124 * Returns the new parser output or NULL
2125 */
2126xmlOutputBufferPtr
2127xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2128 xmlOutputCloseCallback ioclose, void *ioctx,
2129 xmlCharEncodingHandlerPtr encoder) {
2130 xmlOutputBufferPtr ret;
2131
2132 if (iowrite == NULL) return(NULL);
2133
2134 ret = xmlAllocOutputBuffer(encoder);
2135 if (ret != NULL) {
2136 ret->context = (void *) ioctx;
2137 ret->writecallback = iowrite;
2138 ret->closecallback = ioclose;
2139 }
2140
2141 return(ret);
2142}
2143
2144/**
2145 * xmlParserInputBufferPush:
2146 * @in: a buffered parser input
2147 * @len: the size in bytes of the array.
2148 * @buf: an char array
2149 *
2150 * Push the content of the arry in the input buffer
2151 * This routine handle the I18N transcoding to internal UTF-8
2152 * This is used when operating the parser in progressive (push) mode.
2153 *
2154 * Returns the number of chars read and stored in the buffer, or -1
2155 * in case of error.
2156 */
2157int
2158xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2159 int len, const char *buf) {
2160 int nbchars = 0;
2161
2162 if (len < 0) return(0);
2163 if (in->encoder != NULL) {
2164 /*
2165 * Store the data in the incoming raw buffer
2166 */
2167 if (in->raw == NULL) {
2168 in->raw = xmlBufferCreate();
2169 }
2170 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2171
2172 /*
2173 * convert as much as possible to the parser reading buffer.
2174 */
2175 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2176 if (nbchars < 0) {
2177 xmlGenericError(xmlGenericErrorContext,
2178 "xmlParserInputBufferPush: encoder error\n");
2179 return(-1);
2180 }
2181 } else {
2182 nbchars = len;
2183 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2184 }
2185#ifdef DEBUG_INPUT
2186 xmlGenericError(xmlGenericErrorContext,
2187 "I/O: pushed %d chars, buffer %d/%d\n",
2188 nbchars, in->buffer->use, in->buffer->size);
2189#endif
2190 return(nbchars);
2191}
2192
2193/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002194 * endOfInput:
2195 *
2196 * When reading from an Input channel indicated end of file or error
2197 * don't reread from it again.
2198 */
2199static int
2200endOfInput (void * context ATTRIBUTE_UNUSED,
2201 char * buffer ATTRIBUTE_UNUSED,
2202 int len ATTRIBUTE_UNUSED) {
2203 return(0);
2204}
2205
2206/**
Owen Taylor3473f882001-02-23 17:55:21 +00002207 * xmlParserInputBufferGrow:
2208 * @in: a buffered parser input
2209 * @len: indicative value of the amount of chars to read
2210 *
2211 * Grow up the content of the input buffer, the old data are preserved
2212 * This routine handle the I18N transcoding to internal UTF-8
2213 * This routine is used when operating the parser in normal (pull) mode
2214 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002215 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002216 * onto in->buffer or in->raw
2217 *
2218 * Returns the number of chars read and stored in the buffer, or -1
2219 * in case of error.
2220 */
2221int
2222xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2223 char *buffer = NULL;
2224 int res = 0;
2225 int nbchars = 0;
2226 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002227 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002228
2229 if ((len <= MINLEN) && (len != 4))
2230 len = MINLEN;
2231 buffree = in->buffer->size - in->buffer->use;
2232 if (buffree <= 0) {
2233 xmlGenericError(xmlGenericErrorContext,
2234 "xmlParserInputBufferGrow : buffer full !\n");
2235 return(0);
2236 }
2237 if (len > buffree)
2238 len = buffree;
2239
Daniel Veillarde5354492002-05-16 08:43:22 +00002240 needSize = in->buffer->use + len + 1;
2241 if (needSize > in->buffer->size){
2242 if (!xmlBufferResize(in->buffer, needSize)){
2243 xmlGenericError(xmlGenericErrorContext,
2244 "xmlBufferAdd : out of memory!\n");
2245 return(0);
2246 }
Owen Taylor3473f882001-02-23 17:55:21 +00002247 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002248 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002249
2250 /*
2251 * Call the read method for this I/O type.
2252 */
2253 if (in->readcallback != NULL) {
2254 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002255 if (res <= 0)
2256 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002257 } else {
2258 xmlGenericError(xmlGenericErrorContext,
2259 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002260 return(-1);
2261 }
2262 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002263 return(-1);
2264 }
2265 len = res;
2266 if (in->encoder != NULL) {
2267 /*
2268 * Store the data in the incoming raw buffer
2269 */
2270 if (in->raw == NULL) {
2271 in->raw = xmlBufferCreate();
2272 }
2273 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2274
2275 /*
2276 * convert as much as possible to the parser reading buffer.
2277 */
2278 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2279 if (nbchars < 0) {
2280 xmlGenericError(xmlGenericErrorContext,
2281 "xmlParserInputBufferGrow: encoder error\n");
2282 return(-1);
2283 }
2284 } else {
2285 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002286 in->buffer->use += nbchars;
2287 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002288 }
2289#ifdef DEBUG_INPUT
2290 xmlGenericError(xmlGenericErrorContext,
2291 "I/O: read %d chars, buffer %d/%d\n",
2292 nbchars, in->buffer->use, in->buffer->size);
2293#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002294 return(nbchars);
2295}
2296
2297/**
2298 * xmlParserInputBufferRead:
2299 * @in: a buffered parser input
2300 * @len: indicative value of the amount of chars to read
2301 *
2302 * Refresh the content of the input buffer, the old data are considered
2303 * consumed
2304 * This routine handle the I18N transcoding to internal UTF-8
2305 *
2306 * Returns the number of chars read and stored in the buffer, or -1
2307 * in case of error.
2308 */
2309int
2310xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2311 /* xmlBufferEmpty(in->buffer); */
2312 if (in->readcallback != NULL)
2313 return(xmlParserInputBufferGrow(in, len));
2314 else
2315 return(-1);
2316}
2317
2318/**
2319 * xmlOutputBufferWrite:
2320 * @out: a buffered parser output
2321 * @len: the size in bytes of the array.
2322 * @buf: an char array
2323 *
2324 * Write the content of the array in the output I/O buffer
2325 * This routine handle the I18N transcoding from internal UTF-8
2326 * The buffer is lossless, i.e. will store in case of partial
2327 * or delayed writes.
2328 *
2329 * Returns the number of chars immediately written, or -1
2330 * in case of error.
2331 */
2332int
2333xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2334 int nbchars = 0; /* number of chars to output to I/O */
2335 int ret; /* return from function call */
2336 int written = 0; /* number of char written to I/O so far */
2337 int chunk; /* number of byte curreent processed from buf */
2338
2339 if (len < 0) return(0);
2340
2341 do {
2342 chunk = len;
2343 if (chunk > 4 * MINLEN)
2344 chunk = 4 * MINLEN;
2345
2346 /*
2347 * first handle encoding stuff.
2348 */
2349 if (out->encoder != NULL) {
2350 /*
2351 * Store the data in the incoming raw buffer
2352 */
2353 if (out->conv == NULL) {
2354 out->conv = xmlBufferCreate();
2355 }
2356 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2357
2358 if ((out->buffer->use < MINLEN) && (chunk == len))
2359 goto done;
2360
2361 /*
2362 * convert as much as possible to the parser reading buffer.
2363 */
2364 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2365 if (ret < 0) {
2366 xmlGenericError(xmlGenericErrorContext,
2367 "xmlOutputBufferWrite: encoder error\n");
2368 return(-1);
2369 }
2370 nbchars = out->conv->use;
2371 } else {
2372 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2373 nbchars = out->buffer->use;
2374 }
2375 buf += chunk;
2376 len -= chunk;
2377
2378 if ((nbchars < MINLEN) && (len <= 0))
2379 goto done;
2380
2381 if (out->writecallback) {
2382 /*
2383 * second write the stuff to the I/O channel
2384 */
2385 if (out->encoder != NULL) {
2386 ret = out->writecallback(out->context,
2387 (const char *)out->conv->content, nbchars);
2388 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002389 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002390 } else {
2391 ret = out->writecallback(out->context,
2392 (const char *)out->buffer->content, nbchars);
2393 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002394 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002395 }
2396 if (ret < 0) {
2397 xmlGenericError(xmlGenericErrorContext,
2398 "I/O: error %d writing %d bytes\n", ret, nbchars);
2399 return(ret);
2400 }
2401 out->written += ret;
2402 }
2403 written += nbchars;
2404 } while (len > 0);
2405
2406done:
2407#ifdef DEBUG_INPUT
2408 xmlGenericError(xmlGenericErrorContext,
2409 "I/O: wrote %d chars\n", written);
2410#endif
2411 return(written);
2412}
2413
2414/**
2415 * xmlOutputBufferWriteString:
2416 * @out: a buffered parser output
2417 * @str: a zero terminated C string
2418 *
2419 * Write the content of the string in the output I/O buffer
2420 * This routine handle the I18N transcoding from internal UTF-8
2421 * The buffer is lossless, i.e. will store in case of partial
2422 * or delayed writes.
2423 *
2424 * Returns the number of chars immediately written, or -1
2425 * in case of error.
2426 */
2427int
2428xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2429 int len;
2430
2431 if (str == NULL)
2432 return(-1);
2433 len = strlen(str);
2434
2435 if (len > 0)
2436 return(xmlOutputBufferWrite(out, len, str));
2437 return(len);
2438}
2439
2440/**
2441 * xmlOutputBufferFlush:
2442 * @out: a buffered output
2443 *
2444 * flushes the output I/O channel
2445 *
2446 * Returns the number of byte written or -1 in case of error.
2447 */
2448int
2449xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2450 int nbchars = 0, ret = 0;
2451
2452 /*
2453 * first handle encoding stuff.
2454 */
2455 if ((out->conv != NULL) && (out->encoder != NULL)) {
2456 /*
2457 * convert as much as possible to the parser reading buffer.
2458 */
2459 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2460 if (nbchars < 0) {
2461 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002462 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002463 return(-1);
2464 }
2465 }
2466
2467 /*
2468 * second flush the stuff to the I/O channel
2469 */
2470 if ((out->conv != NULL) && (out->encoder != NULL) &&
2471 (out->writecallback != NULL)) {
2472 ret = out->writecallback(out->context,
2473 (const char *)out->conv->content, out->conv->use);
2474 if (ret >= 0)
2475 xmlBufferShrink(out->conv, ret);
2476 } else if (out->writecallback != NULL) {
2477 ret = out->writecallback(out->context,
2478 (const char *)out->buffer->content, out->buffer->use);
2479 if (ret >= 0)
2480 xmlBufferShrink(out->buffer, ret);
2481 }
2482 if (ret < 0) {
2483 xmlGenericError(xmlGenericErrorContext,
2484 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2485 return(ret);
2486 }
2487 out->written += ret;
2488
2489#ifdef DEBUG_INPUT
2490 xmlGenericError(xmlGenericErrorContext,
2491 "I/O: flushed %d chars\n", ret);
2492#endif
2493 return(ret);
2494}
2495
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002496/**
Owen Taylor3473f882001-02-23 17:55:21 +00002497 * xmlParserGetDirectory:
2498 * @filename: the path to a file
2499 *
2500 * lookup the directory for that file
2501 *
2502 * Returns a new allocated string containing the directory, or NULL.
2503 */
2504char *
2505xmlParserGetDirectory(const char *filename) {
2506 char *ret = NULL;
2507 char dir[1024];
2508 char *cur;
2509 char sep = '/';
2510
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002511#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2512 return NULL;
2513#endif
2514
Owen Taylor3473f882001-02-23 17:55:21 +00002515 if (xmlInputCallbackInitialized == 0)
2516 xmlRegisterDefaultInputCallbacks();
2517
2518 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002519#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002520 sep = '\\';
2521#endif
2522
2523 strncpy(dir, filename, 1023);
2524 dir[1023] = 0;
2525 cur = &dir[strlen(dir)];
2526 while (cur > dir) {
2527 if (*cur == sep) break;
2528 cur --;
2529 }
2530 if (*cur == sep) {
2531 if (cur == dir) dir[1] = 0;
2532 else *cur = 0;
2533 ret = xmlMemStrdup(dir);
2534 } else {
2535 if (getcwd(dir, 1024) != NULL) {
2536 dir[1023] = 0;
2537 ret = xmlMemStrdup(dir);
2538 }
2539 }
2540 return(ret);
2541}
2542
2543/****************************************************************
2544 * *
2545 * External entities loading *
2546 * *
2547 ****************************************************************/
2548
Daniel Veillard561b7f82002-03-20 21:55:57 +00002549#ifdef LIBXML_CATALOG_ENABLED
2550static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002551#ifdef HAVE_STAT
2552 int ret;
2553 struct stat info;
2554 const char *path;
2555
2556 if (URL == NULL)
2557 return(0);
2558
Daniel Veillardf4862f02002-09-10 11:13:43 +00002559 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
2560#if defined (_WIN32) && !defined(__CYGWIN__)
2561 path = &URL[17];
2562#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002563 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002564#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002565 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002566#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002567 path = &URL[8];
2568#else
2569 path = &URL[7];
2570#endif
2571 } else
2572 path = URL;
2573 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002574 if (ret == 0)
2575 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002576#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002577 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002578}
Daniel Veillard561b7f82002-03-20 21:55:57 +00002579#endif
Daniel Veillard6990bf32001-08-23 21:17:48 +00002580
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002581/**
Owen Taylor3473f882001-02-23 17:55:21 +00002582 * xmlDefaultExternalEntityLoader:
2583 * @URL: the URL for the entity to load
2584 * @ID: the System ID for the entity to load
2585 * @ctxt: the context in which the entity is called or NULL
2586 *
2587 * By default we don't load external entitites, yet.
2588 *
2589 * Returns a new allocated xmlParserInputPtr, or NULL.
2590 */
2591static
2592xmlParserInputPtr
2593xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2594 xmlParserCtxtPtr ctxt) {
2595 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002596 xmlChar *resource = NULL;
2597#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002598 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002599#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002600
2601#ifdef DEBUG_EXTERNAL_ENTITIES
2602 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002603 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002604#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002605#ifdef LIBXML_CATALOG_ENABLED
2606 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002607 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002608 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002609 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002610 pref = xmlCatalogGetDefaults();
2611
Daniel Veillard561b7f82002-03-20 21:55:57 +00002612 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002613 /*
2614 * Do a local lookup
2615 */
2616 if ((ctxt->catalogs != NULL) &&
2617 ((pref == XML_CATA_ALLOW_ALL) ||
2618 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2619 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2620 (const xmlChar *)ID,
2621 (const xmlChar *)URL);
2622 }
2623 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002624 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002625 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002626 if ((resource == NULL) &&
2627 ((pref == XML_CATA_ALLOW_ALL) ||
2628 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002629 resource = xmlCatalogResolve((const xmlChar *)ID,
2630 (const xmlChar *)URL);
2631 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002632 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002633 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002634
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002635 /*
2636 * TODO: do an URI lookup on the reference
2637 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002638 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002639 xmlChar *tmp = NULL;
2640
2641 if ((ctxt->catalogs != NULL) &&
2642 ((pref == XML_CATA_ALLOW_ALL) ||
2643 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2644 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2645 }
2646 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002647 ((pref == XML_CATA_ALLOW_ALL) ||
2648 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002649 tmp = xmlCatalogResolveURI(resource);
2650 }
2651
2652 if (tmp != NULL) {
2653 xmlFree(resource);
2654 resource = tmp;
2655 }
2656 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002657 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002658#endif
2659
2660 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002661 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002662
2663 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002664 if (ID == NULL)
2665 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002666 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2667 (ctxt->sax->error != NULL))
2668 ctxt->sax->error(ctxt,
2669 "failed to load external entity \"%s\"\n", ID);
2670 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002671 ctxt->sax->warning(ctxt,
2672 "failed to load external entity \"%s\"\n", ID);
2673 return(NULL);
2674 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002675 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002676 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002677 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2678 (ctxt->sax->error != NULL))
2679 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002680 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002681 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002682 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002683 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002684 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002685 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002686 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002687 return(ret);
2688}
2689
2690static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2691 xmlDefaultExternalEntityLoader;
2692
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002693/**
Owen Taylor3473f882001-02-23 17:55:21 +00002694 * xmlSetExternalEntityLoader:
2695 * @f: the new entity resolver function
2696 *
2697 * Changes the defaultexternal entity resolver function for the application
2698 */
2699void
2700xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2701 xmlCurrentExternalEntityLoader = f;
2702}
2703
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002704/**
Owen Taylor3473f882001-02-23 17:55:21 +00002705 * xmlGetExternalEntityLoader:
2706 *
2707 * Get the default external entity resolver function for the application
2708 *
2709 * Returns the xmlExternalEntityLoader function pointer
2710 */
2711xmlExternalEntityLoader
2712xmlGetExternalEntityLoader(void) {
2713 return(xmlCurrentExternalEntityLoader);
2714}
2715
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002716/**
Owen Taylor3473f882001-02-23 17:55:21 +00002717 * xmlLoadExternalEntity:
2718 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002719 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002720 * @ctxt: the context in which the entity is called or NULL
2721 *
2722 * Load an external entity, note that the use of this function for
2723 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002724 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002725 *
2726 * Returns the xmlParserInputPtr or NULL
2727 */
2728xmlParserInputPtr
2729xmlLoadExternalEntity(const char *URL, const char *ID,
2730 xmlParserCtxtPtr ctxt) {
2731 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2732}
2733
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002734/************************************************************************
2735 * *
2736 * Disabling Network access *
2737 * *
2738 ************************************************************************/
2739
2740#ifdef LIBXML_CATALOG_ENABLED
2741static int
2742xmlNoNetExists(const char *URL)
2743{
2744#ifdef HAVE_STAT
2745 int ret;
2746 struct stat info;
2747 const char *path;
2748
2749 if (URL == NULL)
2750 return (0);
2751
Daniel Veillardf4862f02002-09-10 11:13:43 +00002752 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
2753#if defined (_WIN32) && !defined(__CYGWIN__)
2754 path = &URL[17];
2755#else
2756 path = &URL[16];
2757#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002758 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002759#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002760 path = &URL[8];
2761#else
2762 path = &URL[7];
2763#endif
2764 } else
2765 path = URL;
2766 ret = stat(path, &info);
2767 if (ret == 0)
2768 return (1);
2769#endif
2770 return (0);
2771}
2772#endif
2773
2774/**
2775 * xmlNoNetExternalEntityLoader:
2776 * @URL: the URL for the entity to load
2777 * @ID: the System ID for the entity to load
2778 * @ctxt: the context in which the entity is called or NULL
2779 *
2780 * A specific entity loader disabling network accesses, though still
2781 * allowing local catalog accesses for resolution.
2782 *
2783 * Returns a new allocated xmlParserInputPtr, or NULL.
2784 */
2785xmlParserInputPtr
2786xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2787 xmlParserCtxtPtr ctxt) {
2788 xmlParserInputPtr input = NULL;
2789 xmlChar *resource = NULL;
2790
2791#ifdef LIBXML_CATALOG_ENABLED
2792 xmlCatalogAllow pref;
2793
2794 /*
2795 * If the resource doesn't exists as a file,
2796 * try to load it from the resource pointed in the catalogs
2797 */
2798 pref = xmlCatalogGetDefaults();
2799
2800 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2801 /*
2802 * Do a local lookup
2803 */
2804 if ((ctxt->catalogs != NULL) &&
2805 ((pref == XML_CATA_ALLOW_ALL) ||
2806 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2807 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2808 (const xmlChar *)ID,
2809 (const xmlChar *)URL);
2810 }
2811 /*
2812 * Try a global lookup
2813 */
2814 if ((resource == NULL) &&
2815 ((pref == XML_CATA_ALLOW_ALL) ||
2816 (pref == XML_CATA_ALLOW_GLOBAL))) {
2817 resource = xmlCatalogResolve((const xmlChar *)ID,
2818 (const xmlChar *)URL);
2819 }
2820 if ((resource == NULL) && (URL != NULL))
2821 resource = xmlStrdup((const xmlChar *) URL);
2822
2823 /*
2824 * TODO: do an URI lookup on the reference
2825 */
2826 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2827 xmlChar *tmp = NULL;
2828
2829 if ((ctxt->catalogs != NULL) &&
2830 ((pref == XML_CATA_ALLOW_ALL) ||
2831 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2832 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2833 }
2834 if ((tmp == NULL) &&
2835 ((pref == XML_CATA_ALLOW_ALL) ||
2836 (pref == XML_CATA_ALLOW_GLOBAL))) {
2837 tmp = xmlCatalogResolveURI(resource);
2838 }
2839
2840 if (tmp != NULL) {
2841 xmlFree(resource);
2842 resource = tmp;
2843 }
2844 }
2845 }
2846#endif
2847 if (resource == NULL)
2848 resource = (xmlChar *) URL;
2849
2850 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002851 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2852 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002853 xmlGenericError(xmlGenericErrorContext,
2854 "Attempt to load network entity %s \n", resource);
2855
2856 if (resource != (xmlChar *) URL)
2857 xmlFree(resource);
2858 return(NULL);
2859 }
2860 }
2861 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2862 if (resource != (xmlChar *) URL)
2863 xmlFree(resource);
2864 return(input);
2865}
2866