blob: cbc542cc872750631cbd74958001ff080a290f4e [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
Daniel Veillard71531f32003-02-05 13:19:53 +0000394 *
395 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000396 */
397void *
398xmlFileOpen (const char *filename) {
399 char *unescaped;
400 void *retval;
401 unescaped = xmlURIUnescapeString(filename, 0, NULL);
402 if (unescaped != NULL) {
403 retval = xmlFileOpen_real(unescaped);
404 } else {
405 retval = xmlFileOpen_real(filename);
406 }
407 xmlFree(unescaped);
408 return retval;
409}
410
411/**
Owen Taylor3473f882001-02-23 17:55:21 +0000412 * xmlFileOpenW:
413 * @filename: the URI for matching
414 *
415 * output to from FILE *,
416 * if @filename is "-" then the standard output is used
417 *
418 * Returns an I/O context or NULL in case of error
419 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000420static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000421xmlFileOpenW (const char *filename) {
422 const char *path = NULL;
423 FILE *fd;
424
425 if (!strcmp(filename, "-")) {
426 fd = stdout;
427 return((void *) fd);
428 }
429
Daniel Veillardf4862f02002-09-10 11:13:43 +0000430 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
431#if defined (_WIN32) && !defined(__CYGWIN__)
432 path = &filename[17];
433#else
Owen Taylor3473f882001-02-23 17:55:21 +0000434 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000435#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000436 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000437#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000438 path = &filename[8];
439#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000440 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000441#endif
442 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000443 path = filename;
444
445 if (path == NULL)
446 return(NULL);
447
448 fd = fopen(path, "w");
449 return((void *) fd);
450}
451
452/**
453 * xmlFileRead:
454 * @context: the I/O context
455 * @buffer: where to drop data
456 * @len: number of bytes to write
457 *
458 * Read @len bytes to @buffer from the I/O channel.
459 *
460 * Returns the number of bytes written
461 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000462int
Owen Taylor3473f882001-02-23 17:55:21 +0000463xmlFileRead (void * context, char * buffer, int len) {
464 return(fread(&buffer[0], 1, len, (FILE *) context));
465}
466
467/**
468 * xmlFileWrite:
469 * @context: the I/O context
470 * @buffer: where to drop data
471 * @len: number of bytes to write
472 *
473 * Write @len bytes from @buffer to the I/O channel.
474 *
475 * Returns the number of bytes written
476 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000477static int
Owen Taylor3473f882001-02-23 17:55:21 +0000478xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000479 int items;
480
481 items = fwrite(&buffer[0], len, 1, (FILE *) context);
482
483 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000484}
485
486/**
487 * xmlFileClose:
488 * @context: the I/O context
489 *
490 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000491 *
492 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000493 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000494int
Owen Taylor3473f882001-02-23 17:55:21 +0000495xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000496 FILE *fil;
497
498 fil = (FILE *) context;
499 if (fil == stdin)
500 return(0);
501 if (fil == stdout)
502 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000503 if (fil == stderr)
504 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000505 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000506}
507
508/**
509 * xmlFileFlush:
510 * @context: the I/O context
511 *
512 * Flush an I/O channel
513 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000514static int
Owen Taylor3473f882001-02-23 17:55:21 +0000515xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000516 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000517}
518
519#ifdef HAVE_ZLIB_H
520/************************************************************************
521 * *
522 * I/O for compressed file accesses *
523 * *
524 ************************************************************************/
525/**
526 * xmlGzfileMatch:
527 * @filename: the URI for matching
528 *
529 * input from compressed file test
530 *
531 * Returns 1 if matches, 0 otherwise
532 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000533static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000534xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000535 return(1);
536}
537
538/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000539 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000540 * @filename: the URI for matching
541 *
542 * input from compressed file open
543 * if @filename is " " then the standard input is used
544 *
545 * Returns an I/O context or NULL in case of error
546 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000547static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000548xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000549 const char *path = NULL;
550 gzFile fd;
551
552 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000553 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000554 return((void *) fd);
555 }
556
Daniel Veillardf4862f02002-09-10 11:13:43 +0000557 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
558#if defined (_WIN32) && !defined(__CYGWIN__)
559 path = &filename[17];
560#else
Owen Taylor3473f882001-02-23 17:55:21 +0000561 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000562#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000563 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000564#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000565 path = &filename[8];
566#else
Owen Taylor3473f882001-02-23 17:55:21 +0000567 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000568#endif
569 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000570 path = filename;
571
572 if (path == NULL)
573 return(NULL);
574 if (!xmlCheckFilename(path))
575 return(NULL);
576
577 fd = gzopen(path, "rb");
578 return((void *) fd);
579}
580
581/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000582 * xmlGzfileOpen:
583 * @filename: the URI for matching
584 *
585 * Wrapper around xmlGzfileOpen that try it with an unescaped
586 * version of @filename, if this fails fallback to @filename
587 */
588static void *
589xmlGzfileOpen (const char *filename) {
590 char *unescaped;
591 void *retval;
592 unescaped = xmlURIUnescapeString(filename, 0, NULL);
593 if (unescaped != NULL) {
594 retval = xmlGzfileOpen_real(unescaped);
595 } else {
596 retval = xmlGzfileOpen_real(filename);
597 }
598 xmlFree(unescaped);
599 return retval;
600}
601
602/**
Owen Taylor3473f882001-02-23 17:55:21 +0000603 * xmlGzfileOpenW:
604 * @filename: the URI for matching
605 * @compression: the compression factor (0 - 9 included)
606 *
607 * input from compressed file open
608 * if @filename is " " then the standard input is used
609 *
610 * Returns an I/O context or NULL in case of error
611 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000612static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000613xmlGzfileOpenW (const char *filename, int compression) {
614 const char *path = NULL;
615 char mode[15];
616 gzFile fd;
617
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000618 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000619 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000620 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000621 return((void *) fd);
622 }
623
Daniel Veillardf4862f02002-09-10 11:13:43 +0000624 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
625#if defined (_WIN32) && !defined(__CYGWIN__)
626 path = &filename[17];
627#else
Owen Taylor3473f882001-02-23 17:55:21 +0000628 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000629#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000630 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000631#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000632 path = &filename[8];
633#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000634 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000635#endif
636 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000637 path = filename;
638
639 if (path == NULL)
640 return(NULL);
641
642 fd = gzopen(path, mode);
643 return((void *) fd);
644}
645
646/**
647 * xmlGzfileRead:
648 * @context: the I/O context
649 * @buffer: where to drop data
650 * @len: number of bytes to write
651 *
652 * Read @len bytes to @buffer from the compressed I/O channel.
653 *
654 * Returns the number of bytes written
655 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000656static int
Owen Taylor3473f882001-02-23 17:55:21 +0000657xmlGzfileRead (void * context, char * buffer, int len) {
658 return(gzread((gzFile) context, &buffer[0], len));
659}
660
661/**
662 * xmlGzfileWrite:
663 * @context: the I/O context
664 * @buffer: where to drop data
665 * @len: number of bytes to write
666 *
667 * Write @len bytes from @buffer to the compressed I/O channel.
668 *
669 * Returns the number of bytes written
670 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static int
Owen Taylor3473f882001-02-23 17:55:21 +0000672xmlGzfileWrite (void * context, const char * buffer, int len) {
673 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
674}
675
676/**
677 * xmlGzfileClose:
678 * @context: the I/O context
679 *
680 * Close a compressed I/O channel
681 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000682static int
Owen Taylor3473f882001-02-23 17:55:21 +0000683xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000684 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000685}
686#endif /* HAVE_ZLIB_H */
687
688#ifdef LIBXML_HTTP_ENABLED
689/************************************************************************
690 * *
691 * I/O for HTTP file accesses *
692 * *
693 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000694
695typedef struct xmlIOHTTPWriteCtxt_
696{
697 int compression;
698
699 char * uri;
700
701 void * doc_buff;
702
703} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
704
705#ifdef HAVE_ZLIB_H
706
707#define DFLT_WBITS ( -15 )
708#define DFLT_MEM_LVL ( 8 )
709#define GZ_MAGIC1 ( 0x1f )
710#define GZ_MAGIC2 ( 0x8b )
711#define LXML_ZLIB_OS_CODE ( 0x03 )
712#define INIT_HTTP_BUFF_SIZE ( 32768 )
713#define DFLT_ZLIB_RATIO ( 5 )
714
715/*
716** Data structure and functions to work with sending compressed data
717** via HTTP.
718*/
719
720typedef struct xmlZMemBuff_
721{
722 unsigned long size;
723 unsigned long crc;
724
725 unsigned char * zbuff;
726 z_stream zctrl;
727
728} xmlZMemBuff, *xmlZMemBuffPtr;
729
730/**
731 * append_reverse_ulong
732 * @buff: Compressed memory buffer
733 * @data: Unsigned long to append
734 *
735 * Append a unsigned long in reverse byte order to the end of the
736 * memory buffer.
737 */
738static void
739append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
740
741 int idx;
742
743 if ( buff == NULL )
744 return;
745
746 /*
747 ** This is plagiarized from putLong in gzio.c (zlib source) where
748 ** the number "4" is hardcoded. If zlib is ever patched to
749 ** support 64 bit file sizes, this code would need to be patched
750 ** as well.
751 */
752
753 for ( idx = 0; idx < 4; idx++ ) {
754 *buff->zctrl.next_out = ( data & 0xff );
755 data >>= 8;
756 buff->zctrl.next_out++;
757 }
758
759 return;
760}
761
762/**
763 *
764 * xmlFreeZMemBuff
765 * @buff: The memory buffer context to clear
766 *
767 * Release all the resources associated with the compressed memory buffer.
768 */
769static void
770xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
771
772 int z_err;
773
774 if ( buff == NULL )
775 return;
776
777 xmlFree( buff->zbuff );
778 z_err = deflateEnd( &buff->zctrl );
779#ifdef DEBUG_HTTP
780 if ( z_err != Z_OK )
781 xmlGenericError( xmlGenericErrorContext,
782 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
783 z_err );
784#endif
785
786 xmlFree( buff );
787 return;
788}
789
790/**
791 * xmlCreateZMemBuff
792 *@compression: Compression value to use
793 *
794 * Create a memory buffer to hold the compressed XML document. The
795 * compressed document in memory will end up being identical to what
796 * would be created if gzopen/gzwrite/gzclose were being used to
797 * write the document to disk. The code for the header/trailer data to
798 * the compression is plagiarized from the zlib source files.
799 */
800static void *
801xmlCreateZMemBuff( int compression ) {
802
803 int z_err;
804 int hdr_lgth;
805 xmlZMemBuffPtr buff = NULL;
806
807 if ( ( compression < 1 ) || ( compression > 9 ) )
808 return ( NULL );
809
810 /* Create the control and data areas */
811
812 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
813 if ( buff == NULL ) {
814 xmlGenericError( xmlGenericErrorContext,
815 "xmlCreateZMemBuff: %s\n",
816 "Failure allocating buffer context." );
817 return ( NULL );
818 }
819
820 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
821 buff->size = INIT_HTTP_BUFF_SIZE;
822 buff->zbuff = xmlMalloc( buff->size );
823 if ( buff->zbuff == NULL ) {
824 xmlFreeZMemBuff( buff );
825 xmlGenericError( xmlGenericErrorContext,
826 "xmlCreateZMemBuff: %s\n",
827 "Failure allocating data buffer." );
828 return ( NULL );
829 }
830
831 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
832 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
833 if ( z_err != Z_OK ) {
834 xmlFreeZMemBuff( buff );
835 buff = NULL;
836 xmlGenericError( xmlGenericErrorContext,
837 "xmlCreateZMemBuff: %s %d\n",
838 "Error initializing compression context. ZLIB error:",
839 z_err );
840 return ( NULL );
841 }
842
843 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +0000844 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000845 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
846 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +0000847 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
848 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
849 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
850 buff->zctrl.avail_out = buff->size - hdr_lgth;
851
852 return ( buff );
853}
854
855/**
856 * xmlZMemBuffExtend
857 * @buff: Buffer used to compress and consolidate data.
858 * @ext_amt: Number of bytes to extend the buffer.
859 *
860 * Extend the internal buffer used to store the compressed data by the
861 * specified amount.
862 *
863 * Returns 0 on success or -1 on failure to extend the buffer. On failure
864 * the original buffer still exists at the original size.
865 */
866static int
867xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
868
869 int rc = -1;
870 size_t new_size;
871 size_t cur_used;
872
873 unsigned char * tmp_ptr = NULL;
874
875 if ( buff == NULL )
876 return ( -1 );
877
878 else if ( ext_amt == 0 )
879 return ( 0 );
880
881 cur_used = buff->zctrl.next_out - buff->zbuff;
882 new_size = buff->size + ext_amt;
883
884#ifdef DEBUG_HTTP
885 if ( cur_used > new_size )
886 xmlGenericError( xmlGenericErrorContext,
887 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
888 "Buffer overwrite detected during compressed memory",
889 "buffer extension. Overflowed by",
890 (cur_used - new_size ) );
891#endif
892
893 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
894 if ( tmp_ptr != NULL ) {
895 rc = 0;
896 buff->size = new_size;
897 buff->zbuff = tmp_ptr;
898 buff->zctrl.next_out = tmp_ptr + cur_used;
899 buff->zctrl.avail_out = new_size - cur_used;
900 }
901 else {
902 xmlGenericError( xmlGenericErrorContext,
903 "xmlZMemBuffExtend: %s %lu bytes.\n",
904 "Allocation failure extending output buffer to",
905 new_size );
906 }
907
908 return ( rc );
909}
910
911/**
912 * xmlZMemBuffAppend
913 * @buff: Buffer used to compress and consolidate data
914 * @src: Uncompressed source content to append to buffer
915 * @len: Length of source data to append to buffer
916 *
917 * Compress and append data to the internal buffer. The data buffer
918 * will be expanded if needed to store the additional data.
919 *
920 * Returns the number of bytes appended to the buffer or -1 on error.
921 */
922static int
923xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
924
925 int z_err;
926 size_t min_accept;
927
928 if ( ( buff == NULL ) || ( src == NULL ) )
929 return ( -1 );
930
931 buff->zctrl.avail_in = len;
932 buff->zctrl.next_in = (unsigned char *)src;
933 while ( buff->zctrl.avail_in > 0 ) {
934 /*
935 ** Extend the buffer prior to deflate call if a reasonable amount
936 ** of output buffer space is not available.
937 */
938 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
939 if ( buff->zctrl.avail_out <= min_accept ) {
940 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
941 return ( -1 );
942 }
943
944 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
945 if ( z_err != Z_OK ) {
946 xmlGenericError( xmlGenericErrorContext,
947 "xmlZMemBuffAppend: %s %d %s - %d",
948 "Compression error while appending",
949 len, "bytes to buffer. ZLIB error", z_err );
950 return ( -1 );
951 }
952 }
953
954 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
955
956 return ( len );
957}
958
959/**
960 * xmlZMemBuffGetContent
961 * @buff: Compressed memory content buffer
962 * @data_ref: Pointer reference to point to compressed content
963 *
964 * Flushes the compression buffers, appends gzip file trailers and
965 * returns the compressed content and length of the compressed data.
966 * NOTE: The gzip trailer code here is plagiarized from zlib source.
967 *
968 * Returns the length of the compressed data or -1 on error.
969 */
970static int
971xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
972
973 int zlgth = -1;
974 int z_err;
975
976 if ( ( buff == NULL ) || ( data_ref == NULL ) )
977 return ( -1 );
978
979 /* Need to loop until compression output buffers are flushed */
980
981 do
982 {
983 z_err = deflate( &buff->zctrl, Z_FINISH );
984 if ( z_err == Z_OK ) {
985 /* In this case Z_OK means more buffer space needed */
986
987 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
988 return ( -1 );
989 }
990 }
991 while ( z_err == Z_OK );
992
993 /* If the compression state is not Z_STREAM_END, some error occurred */
994
995 if ( z_err == Z_STREAM_END ) {
996
997 /* Need to append the gzip data trailer */
998
999 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1000 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1001 return ( -1 );
1002 }
1003
1004 /*
1005 ** For whatever reason, the CRC and length data are pushed out
1006 ** in reverse byte order. So a memcpy can't be used here.
1007 */
1008
1009 append_reverse_ulong( buff, buff->crc );
1010 append_reverse_ulong( buff, buff->zctrl.total_in );
1011
1012 zlgth = buff->zctrl.next_out - buff->zbuff;
1013 *data_ref = (char *)buff->zbuff;
1014 }
1015
1016 else
1017 xmlGenericError( xmlGenericErrorContext,
1018 "xmlZMemBuffGetContent: %s - %d\n",
1019 "Error flushing zlib buffers. Error code", z_err );
1020
1021 return ( zlgth );
1022}
1023#endif /* HAVE_ZLIB_H */
1024
1025/**
1026 * xmlFreeHTTPWriteCtxt
1027 * @ctxt: Context to cleanup
1028 *
1029 * Free allocated memory and reclaim system resources.
1030 *
1031 * No return value.
1032 */
1033static void
1034xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1035{
1036 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001037 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001038
1039 if ( ctxt->doc_buff != NULL ) {
1040
1041#ifdef HAVE_ZLIB_H
1042 if ( ctxt->compression > 0 ) {
1043 xmlFreeZMemBuff( ctxt->doc_buff );
1044 }
1045 else
1046#endif
1047 {
1048 xmlOutputBufferClose( ctxt->doc_buff );
1049 }
1050 }
1051
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001052 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001053 return;
1054}
1055
1056
Owen Taylor3473f882001-02-23 17:55:21 +00001057/**
1058 * xmlIOHTTPMatch:
1059 * @filename: the URI for matching
1060 *
1061 * check if the URI matches an HTTP one
1062 *
1063 * Returns 1 if matches, 0 otherwise
1064 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001065int
Owen Taylor3473f882001-02-23 17:55:21 +00001066xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001067 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001068 return(1);
1069 return(0);
1070}
1071
1072/**
1073 * xmlIOHTTPOpen:
1074 * @filename: the URI for matching
1075 *
1076 * open an HTTP I/O channel
1077 *
1078 * Returns an I/O context or NULL in case of error
1079 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001080void *
Owen Taylor3473f882001-02-23 17:55:21 +00001081xmlIOHTTPOpen (const char *filename) {
1082 return(xmlNanoHTTPOpen(filename, NULL));
1083}
1084
1085/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001086 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001087 * @post_uri: The destination URI for the document
1088 * @compression: The compression desired for the document.
1089 *
1090 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1091 * request. Non-static as is called from the output buffer creation routine.
1092 *
1093 * Returns an I/O context or NULL in case of error.
1094 */
1095
1096void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001097xmlIOHTTPOpenW(const char *post_uri, int compression)
1098{
Daniel Veillardf012a642001-07-23 19:10:52 +00001099
Daniel Veillard572577e2002-01-18 16:23:55 +00001100 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001101
Daniel Veillard572577e2002-01-18 16:23:55 +00001102 if (post_uri == NULL)
1103 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001104
Daniel Veillard572577e2002-01-18 16:23:55 +00001105 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1106 if (ctxt == NULL) {
1107 xmlGenericError(xmlGenericErrorContext,
1108 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
1109 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001110 }
1111
Daniel Veillard572577e2002-01-18 16:23:55 +00001112 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001113
Daniel Veillard572577e2002-01-18 16:23:55 +00001114 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1115 if (ctxt->uri == NULL) {
1116 xmlGenericError(xmlGenericErrorContext,
1117 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
1118 xmlFreeHTTPWriteCtxt(ctxt);
1119 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001120 }
1121
1122 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001123 * ** Since the document length is required for an HTTP post,
1124 * ** need to put the document into a buffer. A memory buffer
1125 * ** is being used to avoid pushing the data to disk and back.
1126 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001127
1128#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001129 if ((compression > 0) && (compression <= 9)) {
1130
1131 ctxt->compression = compression;
1132 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1133 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001134#endif
1135 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001136 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001137
Daniel Veillard572577e2002-01-18 16:23:55 +00001138 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001139 }
1140
Daniel Veillard572577e2002-01-18 16:23:55 +00001141 if (ctxt->doc_buff == NULL) {
1142 xmlFreeHTTPWriteCtxt(ctxt);
1143 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001144 }
1145
Daniel Veillard572577e2002-01-18 16:23:55 +00001146 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001147}
1148
1149/**
1150 * xmlIOHTTPDfltOpenW
1151 * @post_uri: The destination URI for this document.
1152 *
1153 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1154 * HTTP post command. This function should generally not be used as
1155 * the open callback is short circuited in xmlOutputBufferCreateFile.
1156 *
1157 * Returns a pointer to the new IO context.
1158 */
1159static void *
1160xmlIOHTTPDfltOpenW( const char * post_uri ) {
1161 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1162}
1163
1164/**
Owen Taylor3473f882001-02-23 17:55:21 +00001165 * xmlIOHTTPRead:
1166 * @context: the I/O context
1167 * @buffer: where to drop data
1168 * @len: number of bytes to write
1169 *
1170 * Read @len bytes to @buffer from the I/O channel.
1171 *
1172 * Returns the number of bytes written
1173 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001174int
Owen Taylor3473f882001-02-23 17:55:21 +00001175xmlIOHTTPRead(void * context, char * buffer, int len) {
1176 return(xmlNanoHTTPRead(context, &buffer[0], len));
1177}
1178
1179/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001180 * xmlIOHTTPWrite
1181 * @context: previously opened writing context
1182 * @buffer: data to output to temporary buffer
1183 * @len: bytes to output
1184 *
1185 * Collect data from memory buffer into a temporary file for later
1186 * processing.
1187 *
1188 * Returns number of bytes written.
1189 */
1190
1191static int
1192xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1193
1194 xmlIOHTTPWriteCtxtPtr ctxt = context;
1195
1196 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1197 return ( -1 );
1198
1199 if ( len > 0 ) {
1200
1201 /* Use gzwrite or fwrite as previously setup in the open call */
1202
1203#ifdef HAVE_ZLIB_H
1204 if ( ctxt->compression > 0 )
1205 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1206
1207 else
1208#endif
1209 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1210
1211 if ( len < 0 ) {
1212 xmlGenericError( xmlGenericErrorContext,
1213 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1214 "Error appending to internal buffer.",
1215 "Error sending document to URI",
1216 ctxt->uri );
1217 }
1218 }
1219
1220 return ( len );
1221}
1222
1223
1224/**
Owen Taylor3473f882001-02-23 17:55:21 +00001225 * xmlIOHTTPClose:
1226 * @context: the I/O context
1227 *
1228 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001229 *
1230 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001231 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001232int
Owen Taylor3473f882001-02-23 17:55:21 +00001233xmlIOHTTPClose (void * context) {
1234 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001235 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001236}
Daniel Veillardf012a642001-07-23 19:10:52 +00001237
1238/**
1239 * xmlIOHTTCloseWrite
1240 * @context: The I/O context
1241 * @http_mthd: The HTTP method to be used when sending the data
1242 *
1243 * Close the transmit HTTP I/O channel and actually send the data.
1244 */
1245static int
1246xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1247
1248 int close_rc = -1;
1249 int http_rtn = 0;
1250 int content_lgth = 0;
1251 xmlIOHTTPWriteCtxtPtr ctxt = context;
1252
1253 char * http_content = NULL;
1254 char * content_encoding = NULL;
1255 char * content_type = (char *) "text/xml";
1256 void * http_ctxt = NULL;
1257
1258 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1259 return ( -1 );
1260
1261 /* Retrieve the content from the appropriate buffer */
1262
1263#ifdef HAVE_ZLIB_H
1264
1265 if ( ctxt->compression > 0 ) {
1266 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1267 content_encoding = (char *) "Content-Encoding: gzip";
1268 }
1269 else
1270#endif
1271 {
1272 /* Pull the data out of the memory output buffer */
1273
1274 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1275 http_content = (char *)dctxt->buffer->content;
1276 content_lgth = dctxt->buffer->use;
1277 }
1278
1279 if ( http_content == NULL ) {
1280 xmlGenericError( xmlGenericErrorContext,
1281 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1282 "Error retrieving content.\nUnable to",
1283 http_mthd, "data to URI", ctxt->uri );
1284 }
1285
1286 else {
1287
1288 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1289 &content_type, content_encoding,
1290 content_lgth );
1291
1292 if ( http_ctxt != NULL ) {
1293#ifdef DEBUG_HTTP
1294 /* If testing/debugging - dump reply with request content */
1295
1296 FILE * tst_file = NULL;
1297 char buffer[ 4096 ];
1298 char * dump_name = NULL;
1299 int avail;
1300
1301 xmlGenericError( xmlGenericErrorContext,
1302 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1303 http_mthd, ctxt->uri,
1304 xmlNanoHTTPReturnCode( http_ctxt ) );
1305
1306 /*
1307 ** Since either content or reply may be gzipped,
1308 ** dump them to separate files instead of the
1309 ** standard error context.
1310 */
1311
1312 dump_name = tempnam( NULL, "lxml" );
1313 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001314 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001315
1316 tst_file = fopen( buffer, "w" );
1317 if ( tst_file != NULL ) {
1318 xmlGenericError( xmlGenericErrorContext,
1319 "Transmitted content saved in file: %s\n", buffer );
1320
1321 fwrite( http_content, sizeof( char ),
1322 content_lgth, tst_file );
1323 fclose( tst_file );
1324 }
1325
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001326 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001327 tst_file = fopen( buffer, "w" );
1328 if ( tst_file != NULL ) {
1329 xmlGenericError( xmlGenericErrorContext,
1330 "Reply content saved in file: %s\n", buffer );
1331
1332
1333 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1334 buffer, sizeof( buffer ) )) > 0 ) {
1335
1336 fwrite( buffer, sizeof( char ), avail, tst_file );
1337 }
1338
1339 fclose( tst_file );
1340 }
1341
1342 free( dump_name );
1343 }
1344#endif /* DEBUG_HTTP */
1345
1346 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1347 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1348 close_rc = 0;
1349 else
1350 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001351 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001352 http_mthd, content_lgth,
1353 "bytes to URI", ctxt->uri,
1354 "failed. HTTP return code:", http_rtn );
1355
1356 xmlNanoHTTPClose( http_ctxt );
1357 xmlFree( content_type );
1358 }
1359 }
1360
1361 /* Final cleanups */
1362
1363 xmlFreeHTTPWriteCtxt( ctxt );
1364
1365 return ( close_rc );
1366}
1367
1368/**
1369 * xmlIOHTTPClosePut
1370 *
1371 * @context: The I/O context
1372 *
1373 * Close the transmit HTTP I/O channel and actually send data using a PUT
1374 * HTTP method.
1375 */
1376static int
1377xmlIOHTTPClosePut( void * ctxt ) {
1378 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1379}
1380
1381
1382/**
1383 * xmlIOHTTPClosePost
1384 *
1385 * @context: The I/O context
1386 *
1387 * Close the transmit HTTP I/O channel and actually send data using a POST
1388 * HTTP method.
1389 */
1390static int
1391xmlIOHTTPClosePost( void * ctxt ) {
1392 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1393}
1394
Owen Taylor3473f882001-02-23 17:55:21 +00001395#endif /* LIBXML_HTTP_ENABLED */
1396
1397#ifdef LIBXML_FTP_ENABLED
1398/************************************************************************
1399 * *
1400 * I/O for FTP file accesses *
1401 * *
1402 ************************************************************************/
1403/**
1404 * xmlIOFTPMatch:
1405 * @filename: the URI for matching
1406 *
1407 * check if the URI matches an FTP one
1408 *
1409 * Returns 1 if matches, 0 otherwise
1410 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001411int
Owen Taylor3473f882001-02-23 17:55:21 +00001412xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001413 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001414 return(1);
1415 return(0);
1416}
1417
1418/**
1419 * xmlIOFTPOpen:
1420 * @filename: the URI for matching
1421 *
1422 * open an FTP I/O channel
1423 *
1424 * Returns an I/O context or NULL in case of error
1425 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001426void *
Owen Taylor3473f882001-02-23 17:55:21 +00001427xmlIOFTPOpen (const char *filename) {
1428 return(xmlNanoFTPOpen(filename));
1429}
1430
1431/**
1432 * xmlIOFTPRead:
1433 * @context: the I/O context
1434 * @buffer: where to drop data
1435 * @len: number of bytes to write
1436 *
1437 * Read @len bytes to @buffer from the I/O channel.
1438 *
1439 * Returns the number of bytes written
1440 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001441int
Owen Taylor3473f882001-02-23 17:55:21 +00001442xmlIOFTPRead(void * context, char * buffer, int len) {
1443 return(xmlNanoFTPRead(context, &buffer[0], len));
1444}
1445
1446/**
1447 * xmlIOFTPClose:
1448 * @context: the I/O context
1449 *
1450 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001451 *
1452 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001453 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001454int
Owen Taylor3473f882001-02-23 17:55:21 +00001455xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001456 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001457}
1458#endif /* LIBXML_FTP_ENABLED */
1459
1460
1461/**
1462 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001463 * @matchFunc: the xmlInputMatchCallback
1464 * @openFunc: the xmlInputOpenCallback
1465 * @readFunc: the xmlInputReadCallback
1466 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001467 *
1468 * Register a new set of I/O callback for handling parser input.
1469 *
1470 * Returns the registered handler number or -1 in case of error
1471 */
1472int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001473xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1474 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1475 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001476 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1477 return(-1);
1478 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001479 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1480 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1481 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1482 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001483 return(xmlInputCallbackNr++);
1484}
1485
1486/**
1487 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001488 * @matchFunc: the xmlOutputMatchCallback
1489 * @openFunc: the xmlOutputOpenCallback
1490 * @writeFunc: the xmlOutputWriteCallback
1491 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001492 *
1493 * Register a new set of I/O callback for handling output.
1494 *
1495 * Returns the registered handler number or -1 in case of error
1496 */
1497int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001498xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1499 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1500 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001501 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1502 return(-1);
1503 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001504 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1505 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1506 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1507 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001508 return(xmlOutputCallbackNr++);
1509}
1510
1511/**
1512 * xmlRegisterDefaultInputCallbacks:
1513 *
1514 * Registers the default compiled-in I/O handlers.
1515 */
1516void
Owen Taylor3473f882001-02-23 17:55:21 +00001517xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001518(void) {
1519 if (xmlInputCallbackInitialized)
1520 return;
1521
1522 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1523 xmlFileRead, xmlFileClose);
1524#ifdef HAVE_ZLIB_H
1525 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1526 xmlGzfileRead, xmlGzfileClose);
1527#endif /* HAVE_ZLIB_H */
1528
1529#ifdef LIBXML_HTTP_ENABLED
1530 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1531 xmlIOHTTPRead, xmlIOHTTPClose);
1532#endif /* LIBXML_HTTP_ENABLED */
1533
1534#ifdef LIBXML_FTP_ENABLED
1535 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1536 xmlIOFTPRead, xmlIOFTPClose);
1537#endif /* LIBXML_FTP_ENABLED */
1538 xmlInputCallbackInitialized = 1;
1539}
1540
1541/**
1542 * xmlRegisterDefaultOutputCallbacks:
1543 *
1544 * Registers the default compiled-in I/O handlers.
1545 */
1546void
Owen Taylor3473f882001-02-23 17:55:21 +00001547xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001548(void) {
1549 if (xmlOutputCallbackInitialized)
1550 return;
1551
1552 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1553 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001554
1555#ifdef LIBXML_HTTP_ENABLED
1556 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1557 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1558#endif
1559
Owen Taylor3473f882001-02-23 17:55:21 +00001560/*********************************
1561 No way a-priori to distinguish between gzipped files from
1562 uncompressed ones except opening if existing then closing
1563 and saving with same compression ratio ... a pain.
1564
1565#ifdef HAVE_ZLIB_H
1566 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1567 xmlGzfileWrite, xmlGzfileClose);
1568#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001569
1570 Nor FTP PUT ....
1571#ifdef LIBXML_FTP_ENABLED
1572 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1573 xmlIOFTPWrite, xmlIOFTPClose);
1574#endif
1575 **********************************/
1576 xmlOutputCallbackInitialized = 1;
1577}
1578
Daniel Veillardf012a642001-07-23 19:10:52 +00001579#ifdef LIBXML_HTTP_ENABLED
1580/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001581 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001582 *
1583 * By default, libxml submits HTTP output requests using the "PUT" method.
1584 * Calling this method changes the HTTP output method to use the "POST"
1585 * method instead.
1586 *
1587 */
1588void
1589xmlRegisterHTTPPostCallbacks( void ) {
1590
1591 /* Register defaults if not done previously */
1592
1593 if ( xmlOutputCallbackInitialized == 0 )
1594 xmlRegisterDefaultOutputCallbacks( );
1595
1596 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1597 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1598 return;
1599}
1600#endif
1601
Owen Taylor3473f882001-02-23 17:55:21 +00001602/**
1603 * xmlAllocParserInputBuffer:
1604 * @enc: the charset encoding if known
1605 *
1606 * Create a buffered parser input for progressive parsing
1607 *
1608 * Returns the new parser input or NULL
1609 */
1610xmlParserInputBufferPtr
1611xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1612 xmlParserInputBufferPtr ret;
1613
1614 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1615 if (ret == NULL) {
1616 xmlGenericError(xmlGenericErrorContext,
1617 "xmlAllocParserInputBuffer : out of memory!\n");
1618 return(NULL);
1619 }
1620 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1621 ret->buffer = xmlBufferCreate();
1622 if (ret->buffer == NULL) {
1623 xmlFree(ret);
1624 return(NULL);
1625 }
1626 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1627 ret->encoder = xmlGetCharEncodingHandler(enc);
1628 if (ret->encoder != NULL)
1629 ret->raw = xmlBufferCreate();
1630 else
1631 ret->raw = NULL;
1632 ret->readcallback = NULL;
1633 ret->closecallback = NULL;
1634 ret->context = NULL;
1635
1636 return(ret);
1637}
1638
1639/**
1640 * xmlAllocOutputBuffer:
1641 * @encoder: the encoding converter or NULL
1642 *
1643 * Create a buffered parser output
1644 *
1645 * Returns the new parser output or NULL
1646 */
1647xmlOutputBufferPtr
1648xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1649 xmlOutputBufferPtr ret;
1650
1651 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1652 if (ret == NULL) {
1653 xmlGenericError(xmlGenericErrorContext,
1654 "xmlAllocOutputBuffer : out of memory!\n");
1655 return(NULL);
1656 }
1657 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1658 ret->buffer = xmlBufferCreate();
1659 if (ret->buffer == NULL) {
1660 xmlFree(ret);
1661 return(NULL);
1662 }
1663 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1664 ret->encoder = encoder;
1665 if (encoder != NULL) {
1666 ret->conv = xmlBufferCreateSize(4000);
1667 /*
1668 * This call is designed to initiate the encoder state
1669 */
1670 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1671 } else
1672 ret->conv = NULL;
1673 ret->writecallback = NULL;
1674 ret->closecallback = NULL;
1675 ret->context = NULL;
1676 ret->written = 0;
1677
1678 return(ret);
1679}
1680
1681/**
1682 * xmlFreeParserInputBuffer:
1683 * @in: a buffered parser input
1684 *
1685 * Free up the memory used by a buffered parser input
1686 */
1687void
1688xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1689 if (in->raw) {
1690 xmlBufferFree(in->raw);
1691 in->raw = NULL;
1692 }
1693 if (in->encoder != NULL) {
1694 xmlCharEncCloseFunc(in->encoder);
1695 }
1696 if (in->closecallback != NULL) {
1697 in->closecallback(in->context);
1698 }
1699 if (in->buffer != NULL) {
1700 xmlBufferFree(in->buffer);
1701 in->buffer = NULL;
1702 }
1703
Owen Taylor3473f882001-02-23 17:55:21 +00001704 xmlFree(in);
1705}
1706
1707/**
1708 * xmlOutputBufferClose:
1709 * @out: a buffered output
1710 *
1711 * flushes and close the output I/O channel
1712 * and free up all the associated resources
1713 *
1714 * Returns the number of byte written or -1 in case of error.
1715 */
1716int
1717xmlOutputBufferClose(xmlOutputBufferPtr out) {
1718 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001719 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001720
1721 if (out == NULL)
1722 return(-1);
1723 if (out->writecallback != NULL)
1724 xmlOutputBufferFlush(out);
1725 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001726 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001727 }
1728 written = out->written;
1729 if (out->conv) {
1730 xmlBufferFree(out->conv);
1731 out->conv = NULL;
1732 }
1733 if (out->encoder != NULL) {
1734 xmlCharEncCloseFunc(out->encoder);
1735 }
1736 if (out->buffer != NULL) {
1737 xmlBufferFree(out->buffer);
1738 out->buffer = NULL;
1739 }
1740
Owen Taylor3473f882001-02-23 17:55:21 +00001741 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001742 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001743}
1744
1745/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001746 * xmlParserInputBufferCreateFname:
1747 * @URI: a C string containing the URI or filename
1748 * @enc: the charset encoding if known
1749 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001750 * Returns the new parser input or NULL
1751 */
1752/**
Owen Taylor3473f882001-02-23 17:55:21 +00001753 * xmlParserInputBufferCreateFilename:
1754 * @URI: a C string containing the URI or filename
1755 * @enc: the charset encoding if known
1756 *
1757 * Create a buffered parser input for the progressive parsing of a file
1758 * If filename is "-' then we use stdin as the input.
1759 * Automatic support for ZLIB/Compress compressed document is provided
1760 * by default if found at compile-time.
1761 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1762 *
1763 * Returns the new parser input or NULL
1764 */
1765xmlParserInputBufferPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001766xmlParserInputBufferCreateFilename
Owen Taylor3473f882001-02-23 17:55:21 +00001767(const char *URI, xmlCharEncoding enc) {
1768 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001769 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001770 void *context = NULL;
Daniel Veillardf4862f02002-09-10 11:13:43 +00001771 char *normalized;
Owen Taylor3473f882001-02-23 17:55:21 +00001772
1773 if (xmlInputCallbackInitialized == 0)
1774 xmlRegisterDefaultInputCallbacks();
1775
1776 if (URI == NULL) return(NULL);
Daniel Veillardf4862f02002-09-10 11:13:43 +00001777 normalized = (char *) xmlNormalizeWindowsPath((const xmlChar *)URI);
1778 if (normalized == NULL) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001779
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001780#ifdef LIBXML_CATALOG_ENABLED
1781#endif
1782
Owen Taylor3473f882001-02-23 17:55:21 +00001783 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001784 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001785 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001786 */
1787 if (context == NULL) {
1788 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1789 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1790 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardf4862f02002-09-10 11:13:43 +00001791 context = xmlInputCallbackTable[i].opencallback(normalized);
Daniel Veillard388236f2001-07-08 18:35:48 +00001792 if (context != NULL)
1793 break;
1794 }
Owen Taylor3473f882001-02-23 17:55:21 +00001795 }
1796 }
Daniel Veillardf4862f02002-09-10 11:13:43 +00001797 xmlFree(normalized);
Owen Taylor3473f882001-02-23 17:55:21 +00001798 if (context == NULL) {
1799 return(NULL);
1800 }
1801
1802 /*
1803 * Allocate the Input buffer front-end.
1804 */
1805 ret = xmlAllocParserInputBuffer(enc);
1806 if (ret != NULL) {
1807 ret->context = context;
1808 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1809 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1810 }
1811 return(ret);
1812}
1813
1814/**
1815 * xmlOutputBufferCreateFilename:
1816 * @URI: a C string containing the URI or filename
1817 * @encoder: the encoding converter or NULL
1818 * @compression: the compression ration (0 none, 9 max).
1819 *
1820 * Create a buffered output for the progressive saving of a file
1821 * If filename is "-' then we use stdout as the output.
1822 * Automatic support for ZLIB/Compress compressed document is provided
1823 * by default if found at compile-time.
1824 * TODO: currently if compression is set, the library only support
1825 * writing to a local file.
1826 *
1827 * Returns the new output or NULL
1828 */
1829xmlOutputBufferPtr
1830xmlOutputBufferCreateFilename(const char *URI,
1831 xmlCharEncodingHandlerPtr encoder,
1832 int compression) {
1833 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001834 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001835 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001836 char *unescaped;
Daniel Veillardf4862f02002-09-10 11:13:43 +00001837 char *normalized;
Owen Taylor3473f882001-02-23 17:55:21 +00001838
Daniel Veillardf012a642001-07-23 19:10:52 +00001839 int is_http_uri = 0; /* Can't change if HTTP disabled */
1840
Owen Taylor3473f882001-02-23 17:55:21 +00001841 if (xmlOutputCallbackInitialized == 0)
1842 xmlRegisterDefaultOutputCallbacks();
1843
1844 if (URI == NULL) return(NULL);
Daniel Veillardf4862f02002-09-10 11:13:43 +00001845 normalized = (char *) xmlNormalizeWindowsPath((const xmlChar *)URI);
1846 if (normalized == NULL) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001847
Daniel Veillardf012a642001-07-23 19:10:52 +00001848#ifdef LIBXML_HTTP_ENABLED
1849 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1850
Daniel Veillardf4862f02002-09-10 11:13:43 +00001851 is_http_uri = xmlIOHTTPMatch( normalized );
Daniel Veillardf012a642001-07-23 19:10:52 +00001852#endif
1853
Owen Taylor3473f882001-02-23 17:55:21 +00001854
1855 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001856 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001857 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001858 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001859 */
Daniel Veillardf4862f02002-09-10 11:13:43 +00001860 unescaped = xmlURIUnescapeString(normalized, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001861 if (unescaped != NULL) {
1862#ifdef HAVE_ZLIB_H
1863 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1864 context = xmlGzfileOpenW(unescaped, compression);
1865 if (context != NULL) {
1866 ret = xmlAllocOutputBuffer(encoder);
1867 if (ret != NULL) {
1868 ret->context = context;
1869 ret->writecallback = xmlGzfileWrite;
1870 ret->closecallback = xmlGzfileClose;
1871 }
1872 xmlFree(unescaped);
Daniel Veillardf4862f02002-09-10 11:13:43 +00001873 xmlFree(normalized);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001874 return(ret);
1875 }
1876 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001877#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001878 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1879 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1880 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1881#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1882 /* Need to pass compression parameter into HTTP open calls */
1883 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1884 context = xmlIOHTTPOpenW(unescaped, compression);
1885 else
1886#endif
1887 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1888 if (context != NULL)
1889 break;
1890 }
1891 }
1892 xmlFree(unescaped);
1893 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001894
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001895 /*
1896 * If this failed try with a non-escaped URI this may be a strange
1897 * filename
1898 */
1899 if (context == NULL) {
1900#ifdef HAVE_ZLIB_H
1901 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Daniel Veillardf4862f02002-09-10 11:13:43 +00001902 context = xmlGzfileOpenW(normalized, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001903 if (context != NULL) {
1904 ret = xmlAllocOutputBuffer(encoder);
1905 if (ret != NULL) {
1906 ret->context = context;
1907 ret->writecallback = xmlGzfileWrite;
1908 ret->closecallback = xmlGzfileClose;
1909 }
Daniel Veillardf4862f02002-09-10 11:13:43 +00001910 xmlFree(normalized);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001911 return(ret);
1912 }
1913 }
1914#endif
1915 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1916 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Daniel Veillardf4862f02002-09-10 11:13:43 +00001917 (xmlOutputCallbackTable[i].matchcallback(normalized) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001918#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1919 /* Need to pass compression parameter into HTTP open calls */
1920 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1921 context = xmlIOHTTPOpenW(URI, compression);
1922 else
1923#endif
1924 context = xmlOutputCallbackTable[i].opencallback(URI);
1925 if (context != NULL)
1926 break;
1927 }
Owen Taylor3473f882001-02-23 17:55:21 +00001928 }
1929 }
Daniel Veillardf4862f02002-09-10 11:13:43 +00001930 xmlFree(normalized);
Daniel Veillardf012a642001-07-23 19:10:52 +00001931
Owen Taylor3473f882001-02-23 17:55:21 +00001932 if (context == NULL) {
1933 return(NULL);
1934 }
1935
1936 /*
1937 * Allocate the Output buffer front-end.
1938 */
1939 ret = xmlAllocOutputBuffer(encoder);
1940 if (ret != NULL) {
1941 ret->context = context;
1942 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1943 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1944 }
1945 return(ret);
1946}
1947
1948/**
1949 * xmlParserInputBufferCreateFile:
1950 * @file: a FILE*
1951 * @enc: the charset encoding if known
1952 *
1953 * Create a buffered parser input for the progressive parsing of a FILE *
1954 * buffered C I/O
1955 *
1956 * Returns the new parser input or NULL
1957 */
1958xmlParserInputBufferPtr
1959xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1960 xmlParserInputBufferPtr ret;
1961
1962 if (xmlInputCallbackInitialized == 0)
1963 xmlRegisterDefaultInputCallbacks();
1964
1965 if (file == NULL) return(NULL);
1966
1967 ret = xmlAllocParserInputBuffer(enc);
1968 if (ret != NULL) {
1969 ret->context = file;
1970 ret->readcallback = xmlFileRead;
1971 ret->closecallback = xmlFileFlush;
1972 }
1973
1974 return(ret);
1975}
1976
1977/**
1978 * xmlOutputBufferCreateFile:
1979 * @file: a FILE*
1980 * @encoder: the encoding converter or NULL
1981 *
1982 * Create a buffered output for the progressive saving to a FILE *
1983 * buffered C I/O
1984 *
1985 * Returns the new parser output or NULL
1986 */
1987xmlOutputBufferPtr
1988xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1989 xmlOutputBufferPtr ret;
1990
1991 if (xmlOutputCallbackInitialized == 0)
1992 xmlRegisterDefaultOutputCallbacks();
1993
1994 if (file == NULL) return(NULL);
1995
1996 ret = xmlAllocOutputBuffer(encoder);
1997 if (ret != NULL) {
1998 ret->context = file;
1999 ret->writecallback = xmlFileWrite;
2000 ret->closecallback = xmlFileFlush;
2001 }
2002
2003 return(ret);
2004}
2005
2006/**
2007 * xmlParserInputBufferCreateFd:
2008 * @fd: a file descriptor number
2009 * @enc: the charset encoding if known
2010 *
2011 * Create a buffered parser input for the progressive parsing for the input
2012 * from a file descriptor
2013 *
2014 * Returns the new parser input or NULL
2015 */
2016xmlParserInputBufferPtr
2017xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2018 xmlParserInputBufferPtr ret;
2019
2020 if (fd < 0) return(NULL);
2021
2022 ret = xmlAllocParserInputBuffer(enc);
2023 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002024 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002025 ret->readcallback = xmlFdRead;
2026 ret->closecallback = xmlFdClose;
2027 }
2028
2029 return(ret);
2030}
2031
2032/**
2033 * xmlParserInputBufferCreateMem:
2034 * @mem: the memory input
2035 * @size: the length of the memory block
2036 * @enc: the charset encoding if known
2037 *
2038 * Create a buffered parser input for the progressive parsing for the input
2039 * from a memory area.
2040 *
2041 * Returns the new parser input or NULL
2042 */
2043xmlParserInputBufferPtr
2044xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2045 xmlParserInputBufferPtr ret;
2046
2047 if (size <= 0) return(NULL);
2048 if (mem == NULL) return(NULL);
2049
2050 ret = xmlAllocParserInputBuffer(enc);
2051 if (ret != NULL) {
2052 ret->context = (void *) mem;
2053 ret->readcallback = (xmlInputReadCallback) xmlNop;
2054 ret->closecallback = NULL;
2055 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2056 }
2057
2058 return(ret);
2059}
2060
2061/**
2062 * xmlOutputBufferCreateFd:
2063 * @fd: a file descriptor number
2064 * @encoder: the encoding converter or NULL
2065 *
2066 * Create a buffered output for the progressive saving
2067 * to a file descriptor
2068 *
2069 * Returns the new parser output or NULL
2070 */
2071xmlOutputBufferPtr
2072xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2073 xmlOutputBufferPtr ret;
2074
2075 if (fd < 0) return(NULL);
2076
2077 ret = xmlAllocOutputBuffer(encoder);
2078 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002079 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002080 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002081 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002082 }
2083
2084 return(ret);
2085}
2086
2087/**
2088 * xmlParserInputBufferCreateIO:
2089 * @ioread: an I/O read function
2090 * @ioclose: an I/O close function
2091 * @ioctx: an I/O handler
2092 * @enc: the charset encoding if known
2093 *
2094 * Create a buffered parser input for the progressive parsing for the input
2095 * from an I/O handler
2096 *
2097 * Returns the new parser input or NULL
2098 */
2099xmlParserInputBufferPtr
2100xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2101 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2102 xmlParserInputBufferPtr ret;
2103
2104 if (ioread == NULL) return(NULL);
2105
2106 ret = xmlAllocParserInputBuffer(enc);
2107 if (ret != NULL) {
2108 ret->context = (void *) ioctx;
2109 ret->readcallback = ioread;
2110 ret->closecallback = ioclose;
2111 }
2112
2113 return(ret);
2114}
2115
2116/**
2117 * xmlOutputBufferCreateIO:
2118 * @iowrite: an I/O write function
2119 * @ioclose: an I/O close function
2120 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002121 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002122 *
2123 * Create a buffered output for the progressive saving
2124 * to an I/O handler
2125 *
2126 * Returns the new parser output or NULL
2127 */
2128xmlOutputBufferPtr
2129xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2130 xmlOutputCloseCallback ioclose, void *ioctx,
2131 xmlCharEncodingHandlerPtr encoder) {
2132 xmlOutputBufferPtr ret;
2133
2134 if (iowrite == NULL) return(NULL);
2135
2136 ret = xmlAllocOutputBuffer(encoder);
2137 if (ret != NULL) {
2138 ret->context = (void *) ioctx;
2139 ret->writecallback = iowrite;
2140 ret->closecallback = ioclose;
2141 }
2142
2143 return(ret);
2144}
2145
2146/**
2147 * xmlParserInputBufferPush:
2148 * @in: a buffered parser input
2149 * @len: the size in bytes of the array.
2150 * @buf: an char array
2151 *
2152 * Push the content of the arry in the input buffer
2153 * This routine handle the I18N transcoding to internal UTF-8
2154 * This is used when operating the parser in progressive (push) mode.
2155 *
2156 * Returns the number of chars read and stored in the buffer, or -1
2157 * in case of error.
2158 */
2159int
2160xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2161 int len, const char *buf) {
2162 int nbchars = 0;
2163
2164 if (len < 0) return(0);
2165 if (in->encoder != NULL) {
2166 /*
2167 * Store the data in the incoming raw buffer
2168 */
2169 if (in->raw == NULL) {
2170 in->raw = xmlBufferCreate();
2171 }
2172 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2173
2174 /*
2175 * convert as much as possible to the parser reading buffer.
2176 */
2177 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2178 if (nbchars < 0) {
2179 xmlGenericError(xmlGenericErrorContext,
2180 "xmlParserInputBufferPush: encoder error\n");
2181 return(-1);
2182 }
2183 } else {
2184 nbchars = len;
2185 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2186 }
2187#ifdef DEBUG_INPUT
2188 xmlGenericError(xmlGenericErrorContext,
2189 "I/O: pushed %d chars, buffer %d/%d\n",
2190 nbchars, in->buffer->use, in->buffer->size);
2191#endif
2192 return(nbchars);
2193}
2194
2195/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002196 * endOfInput:
2197 *
2198 * When reading from an Input channel indicated end of file or error
2199 * don't reread from it again.
2200 */
2201static int
2202endOfInput (void * context ATTRIBUTE_UNUSED,
2203 char * buffer ATTRIBUTE_UNUSED,
2204 int len ATTRIBUTE_UNUSED) {
2205 return(0);
2206}
2207
2208/**
Owen Taylor3473f882001-02-23 17:55:21 +00002209 * xmlParserInputBufferGrow:
2210 * @in: a buffered parser input
2211 * @len: indicative value of the amount of chars to read
2212 *
2213 * Grow up the content of the input buffer, the old data are preserved
2214 * This routine handle the I18N transcoding to internal UTF-8
2215 * This routine is used when operating the parser in normal (pull) mode
2216 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002217 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002218 * onto in->buffer or in->raw
2219 *
2220 * Returns the number of chars read and stored in the buffer, or -1
2221 * in case of error.
2222 */
2223int
2224xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2225 char *buffer = NULL;
2226 int res = 0;
2227 int nbchars = 0;
2228 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002229 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002230
2231 if ((len <= MINLEN) && (len != 4))
2232 len = MINLEN;
2233 buffree = in->buffer->size - in->buffer->use;
2234 if (buffree <= 0) {
2235 xmlGenericError(xmlGenericErrorContext,
2236 "xmlParserInputBufferGrow : buffer full !\n");
2237 return(0);
2238 }
2239 if (len > buffree)
2240 len = buffree;
2241
Daniel Veillarde5354492002-05-16 08:43:22 +00002242 needSize = in->buffer->use + len + 1;
2243 if (needSize > in->buffer->size){
2244 if (!xmlBufferResize(in->buffer, needSize)){
2245 xmlGenericError(xmlGenericErrorContext,
2246 "xmlBufferAdd : out of memory!\n");
2247 return(0);
2248 }
Owen Taylor3473f882001-02-23 17:55:21 +00002249 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002250 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002251
2252 /*
2253 * Call the read method for this I/O type.
2254 */
2255 if (in->readcallback != NULL) {
2256 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002257 if (res <= 0)
2258 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002259 } else {
2260 xmlGenericError(xmlGenericErrorContext,
2261 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002262 return(-1);
2263 }
2264 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002265 return(-1);
2266 }
2267 len = res;
2268 if (in->encoder != NULL) {
2269 /*
2270 * Store the data in the incoming raw buffer
2271 */
2272 if (in->raw == NULL) {
2273 in->raw = xmlBufferCreate();
2274 }
2275 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2276
2277 /*
2278 * convert as much as possible to the parser reading buffer.
2279 */
2280 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2281 if (nbchars < 0) {
2282 xmlGenericError(xmlGenericErrorContext,
2283 "xmlParserInputBufferGrow: encoder error\n");
2284 return(-1);
2285 }
2286 } else {
2287 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002288 in->buffer->use += nbchars;
2289 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002290 }
2291#ifdef DEBUG_INPUT
2292 xmlGenericError(xmlGenericErrorContext,
2293 "I/O: read %d chars, buffer %d/%d\n",
2294 nbchars, in->buffer->use, in->buffer->size);
2295#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002296 return(nbchars);
2297}
2298
2299/**
2300 * xmlParserInputBufferRead:
2301 * @in: a buffered parser input
2302 * @len: indicative value of the amount of chars to read
2303 *
2304 * Refresh the content of the input buffer, the old data are considered
2305 * consumed
2306 * This routine handle the I18N transcoding to internal UTF-8
2307 *
2308 * Returns the number of chars read and stored in the buffer, or -1
2309 * in case of error.
2310 */
2311int
2312xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2313 /* xmlBufferEmpty(in->buffer); */
2314 if (in->readcallback != NULL)
2315 return(xmlParserInputBufferGrow(in, len));
2316 else
2317 return(-1);
2318}
2319
2320/**
2321 * xmlOutputBufferWrite:
2322 * @out: a buffered parser output
2323 * @len: the size in bytes of the array.
2324 * @buf: an char array
2325 *
2326 * Write the content of the array in the output I/O buffer
2327 * This routine handle the I18N transcoding from internal UTF-8
2328 * The buffer is lossless, i.e. will store in case of partial
2329 * or delayed writes.
2330 *
2331 * Returns the number of chars immediately written, or -1
2332 * in case of error.
2333 */
2334int
2335xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2336 int nbchars = 0; /* number of chars to output to I/O */
2337 int ret; /* return from function call */
2338 int written = 0; /* number of char written to I/O so far */
2339 int chunk; /* number of byte curreent processed from buf */
2340
2341 if (len < 0) return(0);
2342
2343 do {
2344 chunk = len;
2345 if (chunk > 4 * MINLEN)
2346 chunk = 4 * MINLEN;
2347
2348 /*
2349 * first handle encoding stuff.
2350 */
2351 if (out->encoder != NULL) {
2352 /*
2353 * Store the data in the incoming raw buffer
2354 */
2355 if (out->conv == NULL) {
2356 out->conv = xmlBufferCreate();
2357 }
2358 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2359
2360 if ((out->buffer->use < MINLEN) && (chunk == len))
2361 goto done;
2362
2363 /*
2364 * convert as much as possible to the parser reading buffer.
2365 */
2366 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2367 if (ret < 0) {
2368 xmlGenericError(xmlGenericErrorContext,
2369 "xmlOutputBufferWrite: encoder error\n");
2370 return(-1);
2371 }
2372 nbchars = out->conv->use;
2373 } else {
2374 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2375 nbchars = out->buffer->use;
2376 }
2377 buf += chunk;
2378 len -= chunk;
2379
2380 if ((nbchars < MINLEN) && (len <= 0))
2381 goto done;
2382
2383 if (out->writecallback) {
2384 /*
2385 * second write the stuff to the I/O channel
2386 */
2387 if (out->encoder != NULL) {
2388 ret = out->writecallback(out->context,
2389 (const char *)out->conv->content, nbchars);
2390 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002391 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002392 } else {
2393 ret = out->writecallback(out->context,
2394 (const char *)out->buffer->content, nbchars);
2395 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002396 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002397 }
2398 if (ret < 0) {
2399 xmlGenericError(xmlGenericErrorContext,
2400 "I/O: error %d writing %d bytes\n", ret, nbchars);
2401 return(ret);
2402 }
2403 out->written += ret;
2404 }
2405 written += nbchars;
2406 } while (len > 0);
2407
2408done:
2409#ifdef DEBUG_INPUT
2410 xmlGenericError(xmlGenericErrorContext,
2411 "I/O: wrote %d chars\n", written);
2412#endif
2413 return(written);
2414}
2415
2416/**
2417 * xmlOutputBufferWriteString:
2418 * @out: a buffered parser output
2419 * @str: a zero terminated C string
2420 *
2421 * Write the content of the string in the output I/O buffer
2422 * This routine handle the I18N transcoding from internal UTF-8
2423 * The buffer is lossless, i.e. will store in case of partial
2424 * or delayed writes.
2425 *
2426 * Returns the number of chars immediately written, or -1
2427 * in case of error.
2428 */
2429int
2430xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2431 int len;
2432
2433 if (str == NULL)
2434 return(-1);
2435 len = strlen(str);
2436
2437 if (len > 0)
2438 return(xmlOutputBufferWrite(out, len, str));
2439 return(len);
2440}
2441
2442/**
2443 * xmlOutputBufferFlush:
2444 * @out: a buffered output
2445 *
2446 * flushes the output I/O channel
2447 *
2448 * Returns the number of byte written or -1 in case of error.
2449 */
2450int
2451xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2452 int nbchars = 0, ret = 0;
2453
2454 /*
2455 * first handle encoding stuff.
2456 */
2457 if ((out->conv != NULL) && (out->encoder != NULL)) {
2458 /*
2459 * convert as much as possible to the parser reading buffer.
2460 */
2461 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2462 if (nbchars < 0) {
2463 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002464 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002465 return(-1);
2466 }
2467 }
2468
2469 /*
2470 * second flush the stuff to the I/O channel
2471 */
2472 if ((out->conv != NULL) && (out->encoder != NULL) &&
2473 (out->writecallback != NULL)) {
2474 ret = out->writecallback(out->context,
2475 (const char *)out->conv->content, out->conv->use);
2476 if (ret >= 0)
2477 xmlBufferShrink(out->conv, ret);
2478 } else if (out->writecallback != NULL) {
2479 ret = out->writecallback(out->context,
2480 (const char *)out->buffer->content, out->buffer->use);
2481 if (ret >= 0)
2482 xmlBufferShrink(out->buffer, ret);
2483 }
2484 if (ret < 0) {
2485 xmlGenericError(xmlGenericErrorContext,
2486 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2487 return(ret);
2488 }
2489 out->written += ret;
2490
2491#ifdef DEBUG_INPUT
2492 xmlGenericError(xmlGenericErrorContext,
2493 "I/O: flushed %d chars\n", ret);
2494#endif
2495 return(ret);
2496}
2497
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002498/**
Owen Taylor3473f882001-02-23 17:55:21 +00002499 * xmlParserGetDirectory:
2500 * @filename: the path to a file
2501 *
2502 * lookup the directory for that file
2503 *
2504 * Returns a new allocated string containing the directory, or NULL.
2505 */
2506char *
2507xmlParserGetDirectory(const char *filename) {
2508 char *ret = NULL;
2509 char dir[1024];
2510 char *cur;
2511 char sep = '/';
2512
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002513#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2514 return NULL;
2515#endif
2516
Owen Taylor3473f882001-02-23 17:55:21 +00002517 if (xmlInputCallbackInitialized == 0)
2518 xmlRegisterDefaultInputCallbacks();
2519
2520 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002521#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002522 sep = '\\';
2523#endif
2524
2525 strncpy(dir, filename, 1023);
2526 dir[1023] = 0;
2527 cur = &dir[strlen(dir)];
2528 while (cur > dir) {
2529 if (*cur == sep) break;
2530 cur --;
2531 }
2532 if (*cur == sep) {
2533 if (cur == dir) dir[1] = 0;
2534 else *cur = 0;
2535 ret = xmlMemStrdup(dir);
2536 } else {
2537 if (getcwd(dir, 1024) != NULL) {
2538 dir[1023] = 0;
2539 ret = xmlMemStrdup(dir);
2540 }
2541 }
2542 return(ret);
2543}
2544
2545/****************************************************************
2546 * *
2547 * External entities loading *
2548 * *
2549 ****************************************************************/
2550
Daniel Veillard561b7f82002-03-20 21:55:57 +00002551#ifdef LIBXML_CATALOG_ENABLED
2552static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002553#ifdef HAVE_STAT
2554 int ret;
2555 struct stat info;
2556 const char *path;
2557
2558 if (URL == NULL)
2559 return(0);
2560
Daniel Veillardf4862f02002-09-10 11:13:43 +00002561 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
2562#if defined (_WIN32) && !defined(__CYGWIN__)
2563 path = &URL[17];
2564#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002565 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002566#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002567 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002568#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002569 path = &URL[8];
2570#else
2571 path = &URL[7];
2572#endif
2573 } else
2574 path = URL;
2575 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002576 if (ret == 0)
2577 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002578#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002579 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002580}
Daniel Veillard561b7f82002-03-20 21:55:57 +00002581#endif
Daniel Veillard6990bf32001-08-23 21:17:48 +00002582
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002583/**
Owen Taylor3473f882001-02-23 17:55:21 +00002584 * xmlDefaultExternalEntityLoader:
2585 * @URL: the URL for the entity to load
2586 * @ID: the System ID for the entity to load
2587 * @ctxt: the context in which the entity is called or NULL
2588 *
2589 * By default we don't load external entitites, yet.
2590 *
2591 * Returns a new allocated xmlParserInputPtr, or NULL.
2592 */
2593static
2594xmlParserInputPtr
2595xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2596 xmlParserCtxtPtr ctxt) {
2597 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002598 xmlChar *resource = NULL;
2599#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002600 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002601#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002602
2603#ifdef DEBUG_EXTERNAL_ENTITIES
2604 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002605 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002606#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002607#ifdef LIBXML_CATALOG_ENABLED
2608 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002609 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002610 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002611 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002612 pref = xmlCatalogGetDefaults();
2613
Daniel Veillard561b7f82002-03-20 21:55:57 +00002614 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002615 /*
2616 * Do a local lookup
2617 */
2618 if ((ctxt->catalogs != NULL) &&
2619 ((pref == XML_CATA_ALLOW_ALL) ||
2620 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2621 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2622 (const xmlChar *)ID,
2623 (const xmlChar *)URL);
2624 }
2625 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002626 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002627 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002628 if ((resource == NULL) &&
2629 ((pref == XML_CATA_ALLOW_ALL) ||
2630 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002631 resource = xmlCatalogResolve((const xmlChar *)ID,
2632 (const xmlChar *)URL);
2633 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002634 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002635 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002636
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002637 /*
2638 * TODO: do an URI lookup on the reference
2639 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002640 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002641 xmlChar *tmp = NULL;
2642
2643 if ((ctxt->catalogs != NULL) &&
2644 ((pref == XML_CATA_ALLOW_ALL) ||
2645 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2646 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2647 }
2648 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002649 ((pref == XML_CATA_ALLOW_ALL) ||
2650 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002651 tmp = xmlCatalogResolveURI(resource);
2652 }
2653
2654 if (tmp != NULL) {
2655 xmlFree(resource);
2656 resource = tmp;
2657 }
2658 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002659 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002660#endif
2661
2662 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002663 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002664
2665 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002666 if (ID == NULL)
2667 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002668 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2669 (ctxt->sax->error != NULL))
2670 ctxt->sax->error(ctxt,
2671 "failed to load external entity \"%s\"\n", ID);
2672 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002673 ctxt->sax->warning(ctxt,
2674 "failed to load external entity \"%s\"\n", ID);
2675 return(NULL);
2676 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002677 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002678 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002679 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2680 (ctxt->sax->error != NULL))
2681 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002682 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002683 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002684 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002685 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002686 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002687 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002688 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002689 return(ret);
2690}
2691
2692static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2693 xmlDefaultExternalEntityLoader;
2694
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002695/**
Owen Taylor3473f882001-02-23 17:55:21 +00002696 * xmlSetExternalEntityLoader:
2697 * @f: the new entity resolver function
2698 *
2699 * Changes the defaultexternal entity resolver function for the application
2700 */
2701void
2702xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2703 xmlCurrentExternalEntityLoader = f;
2704}
2705
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002706/**
Owen Taylor3473f882001-02-23 17:55:21 +00002707 * xmlGetExternalEntityLoader:
2708 *
2709 * Get the default external entity resolver function for the application
2710 *
2711 * Returns the xmlExternalEntityLoader function pointer
2712 */
2713xmlExternalEntityLoader
2714xmlGetExternalEntityLoader(void) {
2715 return(xmlCurrentExternalEntityLoader);
2716}
2717
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002718/**
Owen Taylor3473f882001-02-23 17:55:21 +00002719 * xmlLoadExternalEntity:
2720 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002721 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002722 * @ctxt: the context in which the entity is called or NULL
2723 *
2724 * Load an external entity, note that the use of this function for
2725 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002726 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002727 *
2728 * Returns the xmlParserInputPtr or NULL
2729 */
2730xmlParserInputPtr
2731xmlLoadExternalEntity(const char *URL, const char *ID,
2732 xmlParserCtxtPtr ctxt) {
2733 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2734}
2735
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002736/************************************************************************
2737 * *
2738 * Disabling Network access *
2739 * *
2740 ************************************************************************/
2741
2742#ifdef LIBXML_CATALOG_ENABLED
2743static int
2744xmlNoNetExists(const char *URL)
2745{
2746#ifdef HAVE_STAT
2747 int ret;
2748 struct stat info;
2749 const char *path;
2750
2751 if (URL == NULL)
2752 return (0);
2753
Daniel Veillardf4862f02002-09-10 11:13:43 +00002754 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
2755#if defined (_WIN32) && !defined(__CYGWIN__)
2756 path = &URL[17];
2757#else
2758 path = &URL[16];
2759#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002760 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002761#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002762 path = &URL[8];
2763#else
2764 path = &URL[7];
2765#endif
2766 } else
2767 path = URL;
2768 ret = stat(path, &info);
2769 if (ret == 0)
2770 return (1);
2771#endif
2772 return (0);
2773}
2774#endif
2775
2776/**
2777 * xmlNoNetExternalEntityLoader:
2778 * @URL: the URL for the entity to load
2779 * @ID: the System ID for the entity to load
2780 * @ctxt: the context in which the entity is called or NULL
2781 *
2782 * A specific entity loader disabling network accesses, though still
2783 * allowing local catalog accesses for resolution.
2784 *
2785 * Returns a new allocated xmlParserInputPtr, or NULL.
2786 */
2787xmlParserInputPtr
2788xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2789 xmlParserCtxtPtr ctxt) {
2790 xmlParserInputPtr input = NULL;
2791 xmlChar *resource = NULL;
2792
2793#ifdef LIBXML_CATALOG_ENABLED
2794 xmlCatalogAllow pref;
2795
2796 /*
2797 * If the resource doesn't exists as a file,
2798 * try to load it from the resource pointed in the catalogs
2799 */
2800 pref = xmlCatalogGetDefaults();
2801
2802 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2803 /*
2804 * Do a local lookup
2805 */
2806 if ((ctxt->catalogs != NULL) &&
2807 ((pref == XML_CATA_ALLOW_ALL) ||
2808 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2809 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2810 (const xmlChar *)ID,
2811 (const xmlChar *)URL);
2812 }
2813 /*
2814 * Try a global lookup
2815 */
2816 if ((resource == NULL) &&
2817 ((pref == XML_CATA_ALLOW_ALL) ||
2818 (pref == XML_CATA_ALLOW_GLOBAL))) {
2819 resource = xmlCatalogResolve((const xmlChar *)ID,
2820 (const xmlChar *)URL);
2821 }
2822 if ((resource == NULL) && (URL != NULL))
2823 resource = xmlStrdup((const xmlChar *) URL);
2824
2825 /*
2826 * TODO: do an URI lookup on the reference
2827 */
2828 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2829 xmlChar *tmp = NULL;
2830
2831 if ((ctxt->catalogs != NULL) &&
2832 ((pref == XML_CATA_ALLOW_ALL) ||
2833 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2834 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2835 }
2836 if ((tmp == NULL) &&
2837 ((pref == XML_CATA_ALLOW_ALL) ||
2838 (pref == XML_CATA_ALLOW_GLOBAL))) {
2839 tmp = xmlCatalogResolveURI(resource);
2840 }
2841
2842 if (tmp != NULL) {
2843 xmlFree(resource);
2844 resource = tmp;
2845 }
2846 }
2847 }
2848#endif
2849 if (resource == NULL)
2850 resource = (xmlChar *) URL;
2851
2852 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002853 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2854 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002855 xmlGenericError(xmlGenericErrorContext,
2856 "Attempt to load network entity %s \n", resource);
2857
2858 if (resource != (xmlChar *) URL)
2859 xmlFree(resource);
2860 return(NULL);
2861 }
2862 }
2863 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2864 if (resource != (xmlChar *) URL)
2865 xmlFree(resource);
2866 return(input);
2867}
2868