blob: 949d9c62a2a2b0d9a85fa37119e06df7189e15bf [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>
15#include <errno.h>
16
17#ifdef HAVE_SYS_TYPES_H
18#include <sys/types.h>
19#endif
20#ifdef HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#ifdef HAVE_FCNTL_H
24#include <fcntl.h>
25#endif
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#endif
29#ifdef HAVE_STDLIB_H
30#include <stdlib.h>
31#endif
32#ifdef HAVE_ZLIB_H
33#include <zlib.h>
34#endif
35
36/* Figure a portable way to know if a file is a directory. */
37#ifndef HAVE_STAT
38# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000039 /* MS C library seems to define stat and _stat. The definition
40 is identical. Still, mapping them to each other causes a warning. */
41# ifndef _MSC_VER
42# define stat(x,y) _stat(x,y)
43# endif
Owen Taylor3473f882001-02-23 17:55:21 +000044# define HAVE_STAT
45# endif
46#endif
47#ifdef HAVE_STAT
48# ifndef S_ISDIR
49# ifdef _S_ISDIR
50# define S_ISDIR(x) _S_ISDIR(x)
51# else
52# ifdef S_IFDIR
53# ifndef S_IFMT
54# ifdef _S_IFMT
55# define S_IFMT _S_IFMT
56# endif
57# endif
58# ifdef S_IFMT
59# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
60# endif
61# endif
62# endif
63# endif
64#endif
65
66#include <libxml/xmlmemory.h>
67#include <libxml/parser.h>
68#include <libxml/parserInternals.h>
69#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000070#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000071#include <libxml/nanohttp.h>
72#include <libxml/nanoftp.h>
73#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000074#ifdef LIBXML_CATALOG_ENABLED
75#include <libxml/catalog.h>
76#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000077#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000078
79#ifdef VMS
80#define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
81#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
82#endif
83
Daniel Veillardf012a642001-07-23 19:10:52 +000084/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000085/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000086/* #define DEBUG_INPUT */
87
88#ifdef DEBUG_INPUT
89#define MINLEN 40
90#else
91#define MINLEN 4000
92#endif
93
94/*
95 * Input I/O callback sets
96 */
97typedef struct _xmlInputCallback {
98 xmlInputMatchCallback matchcallback;
99 xmlInputOpenCallback opencallback;
100 xmlInputReadCallback readcallback;
101 xmlInputCloseCallback closecallback;
102} xmlInputCallback;
103
104#define MAX_INPUT_CALLBACK 15
105
Daniel Veillard22090732001-07-16 00:06:07 +0000106static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
107static int xmlInputCallbackNr = 0;
108static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000109
110/*
111 * Output I/O callback sets
112 */
113typedef struct _xmlOutputCallback {
114 xmlOutputMatchCallback matchcallback;
115 xmlOutputOpenCallback opencallback;
116 xmlOutputWriteCallback writecallback;
117 xmlOutputCloseCallback closecallback;
118} xmlOutputCallback;
119
120#define MAX_OUTPUT_CALLBACK 15
121
Daniel Veillard22090732001-07-16 00:06:07 +0000122static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
123static int xmlOutputCallbackNr = 0;
124static int xmlOutputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000126/**
127 * xmlCleanupInputCallbacks:
128 *
129 * clears the entire input callback table. this includes the
130 * compiled-in I/O.
131 */
132void
133xmlCleanupInputCallbacks(void)
134{
135 int i;
136
137 if (!xmlInputCallbackInitialized)
138 return;
139
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000140 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000141 xmlInputCallbackTable[i].matchcallback = NULL;
142 xmlInputCallbackTable[i].opencallback = NULL;
143 xmlInputCallbackTable[i].readcallback = NULL;
144 xmlInputCallbackTable[i].closecallback = NULL;
145 }
146
147 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000148 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000149}
150
151/**
152 * xmlCleanupOutputCallbacks:
153 *
154 * clears the entire output callback table. this includes the
155 * compiled-in I/O callbacks.
156 */
157void
158xmlCleanupOutputCallbacks(void)
159{
160 int i;
161
162 if (!xmlOutputCallbackInitialized)
163 return;
164
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000165 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000166 xmlOutputCallbackTable[i].matchcallback = NULL;
167 xmlOutputCallbackTable[i].opencallback = NULL;
168 xmlOutputCallbackTable[i].writecallback = NULL;
169 xmlOutputCallbackTable[i].closecallback = NULL;
170 }
171
172 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000173 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000174}
175
Owen Taylor3473f882001-02-23 17:55:21 +0000176/************************************************************************
177 * *
178 * Standard I/O for file accesses *
179 * *
180 ************************************************************************/
181
182/**
183 * xmlCheckFilename
184 * @path: the path to check
185 *
186 * function checks to see if @path is a valid source
187 * (file, socket...) for XML.
188 *
189 * if stat is not available on the target machine,
190 * returns 1. if stat fails, returns 0 (if calling
191 * stat on the filename fails, it can't be right).
192 * if stat succeeds and the file is a directory,
193 * sets errno to EISDIR and returns 0. otherwise
194 * returns 1.
195 */
196
197static int
198xmlCheckFilename (const char *path)
199{
200#ifdef HAVE_STAT
201#ifdef S_ISDIR
202 struct stat stat_buffer;
203
204 if (stat(path, &stat_buffer) == -1)
205 return 0;
206
207 if (S_ISDIR(stat_buffer.st_mode)) {
208 errno = EISDIR;
209 return 0;
210 }
211
212#endif
213#endif
214 return 1;
215}
216
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000217static int
Owen Taylor3473f882001-02-23 17:55:21 +0000218xmlNop(void) {
219 return(0);
220}
221
222/**
Owen Taylor3473f882001-02-23 17:55:21 +0000223 * xmlFdRead:
224 * @context: the I/O context
225 * @buffer: where to drop data
226 * @len: number of bytes to read
227 *
228 * Read @len bytes to @buffer from the I/O channel.
229 *
230 * Returns the number of bytes written
231 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000232static int
Owen Taylor3473f882001-02-23 17:55:21 +0000233xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000234 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000235}
236
237/**
238 * xmlFdWrite:
239 * @context: the I/O context
240 * @buffer: where to get data
241 * @len: number of bytes to write
242 *
243 * Write @len bytes from @buffer to the I/O channel.
244 *
245 * Returns the number of bytes written
246 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000247static int
Owen Taylor3473f882001-02-23 17:55:21 +0000248xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000249 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000250}
251
252/**
253 * xmlFdClose:
254 * @context: the I/O context
255 *
256 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000257 *
258 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000259 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000260static int
Owen Taylor3473f882001-02-23 17:55:21 +0000261xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000262 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000263}
264
265/**
266 * xmlFileMatch:
267 * @filename: the URI for matching
268 *
269 * input from FILE *
270 *
271 * Returns 1 if matches, 0 otherwise
272 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000273int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000274xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000275 return(1);
276}
277
278/**
279 * xmlFileOpen:
280 * @filename: the URI for matching
281 *
282 * input from FILE *, supports compressed input
283 * if @filename is " " then the standard input is used
284 *
285 * Returns an I/O context or NULL in case of error
286 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000287void *
Owen Taylor3473f882001-02-23 17:55:21 +0000288xmlFileOpen (const char *filename) {
289 const char *path = NULL;
290 FILE *fd;
291
292 if (!strcmp(filename, "-")) {
293 fd = stdin;
294 return((void *) fd);
295 }
296
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000297 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000298 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000299 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000300#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000301 path = &filename[8];
302#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000303 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000304#endif
305 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000306 path = filename;
307
308 if (path == NULL)
309 return(NULL);
310 if (!xmlCheckFilename(path))
311 return(NULL);
312
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000313#if defined(WIN32) || defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000314 fd = fopen(path, "rb");
315#else
316 fd = fopen(path, "r");
317#endif /* WIN32 */
318 return((void *) fd);
319}
320
321/**
322 * xmlFileOpenW:
323 * @filename: the URI for matching
324 *
325 * output to from FILE *,
326 * if @filename is "-" then the standard output is used
327 *
328 * Returns an I/O context or NULL in case of error
329 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000330static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000331xmlFileOpenW (const char *filename) {
332 const char *path = NULL;
333 FILE *fd;
334
335 if (!strcmp(filename, "-")) {
336 fd = stdout;
337 return((void *) fd);
338 }
339
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000340 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000341 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000342 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000343#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000344 path = &filename[8];
345#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000346 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000347#endif
348 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000349 path = filename;
350
351 if (path == NULL)
352 return(NULL);
353
354 fd = fopen(path, "w");
355 return((void *) fd);
356}
357
358/**
359 * xmlFileRead:
360 * @context: the I/O context
361 * @buffer: where to drop data
362 * @len: number of bytes to write
363 *
364 * Read @len bytes to @buffer from the I/O channel.
365 *
366 * Returns the number of bytes written
367 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000368int
Owen Taylor3473f882001-02-23 17:55:21 +0000369xmlFileRead (void * context, char * buffer, int len) {
370 return(fread(&buffer[0], 1, len, (FILE *) context));
371}
372
373/**
374 * xmlFileWrite:
375 * @context: the I/O context
376 * @buffer: where to drop data
377 * @len: number of bytes to write
378 *
379 * Write @len bytes from @buffer to the I/O channel.
380 *
381 * Returns the number of bytes written
382 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000383static int
Owen Taylor3473f882001-02-23 17:55:21 +0000384xmlFileWrite (void * context, const char * buffer, int len) {
385 return(fwrite(&buffer[0], 1, len, (FILE *) context));
386}
387
388/**
389 * xmlFileClose:
390 * @context: the I/O context
391 *
392 * Close an I/O channel
393 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000394int
Owen Taylor3473f882001-02-23 17:55:21 +0000395xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000396 FILE *fil;
397
398 fil = (FILE *) context;
399 if (fil == stdin)
400 return(0);
401 if (fil == stdout)
402 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000403 if (fil == stderr)
404 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000405 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000406}
407
408/**
409 * xmlFileFlush:
410 * @context: the I/O context
411 *
412 * Flush an I/O channel
413 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000414static int
Owen Taylor3473f882001-02-23 17:55:21 +0000415xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000416 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000417}
418
419#ifdef HAVE_ZLIB_H
420/************************************************************************
421 * *
422 * I/O for compressed file accesses *
423 * *
424 ************************************************************************/
425/**
426 * xmlGzfileMatch:
427 * @filename: the URI for matching
428 *
429 * input from compressed file test
430 *
431 * Returns 1 if matches, 0 otherwise
432 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000433static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000434xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000435 return(1);
436}
437
438/**
439 * xmlGzfileOpen:
440 * @filename: the URI for matching
441 *
442 * input from compressed file open
443 * if @filename is " " then the standard input is used
444 *
445 * Returns an I/O context or NULL in case of error
446 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000447static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000448xmlGzfileOpen (const char *filename) {
449 const char *path = NULL;
450 gzFile fd;
451
452 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000453 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000454 return((void *) fd);
455 }
456
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000457 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000458 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000459 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000460#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000461 path = &filename[8];
462#else
Owen Taylor3473f882001-02-23 17:55:21 +0000463 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000464#endif
465 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000466 path = filename;
467
468 if (path == NULL)
469 return(NULL);
470 if (!xmlCheckFilename(path))
471 return(NULL);
472
473 fd = gzopen(path, "rb");
474 return((void *) fd);
475}
476
477/**
478 * xmlGzfileOpenW:
479 * @filename: the URI for matching
480 * @compression: the compression factor (0 - 9 included)
481 *
482 * input from compressed file open
483 * if @filename is " " then the standard input is used
484 *
485 * Returns an I/O context or NULL in case of error
486 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000487static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000488xmlGzfileOpenW (const char *filename, int compression) {
489 const char *path = NULL;
490 char mode[15];
491 gzFile fd;
492
493 sprintf(mode, "wb%d", compression);
494 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000495 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000496 return((void *) fd);
497 }
498
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000499 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000500 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000501 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000502#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000503 path = &filename[8];
504#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000505 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000506#endif
507 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000508 path = filename;
509
510 if (path == NULL)
511 return(NULL);
512
513 fd = gzopen(path, mode);
514 return((void *) fd);
515}
516
517/**
518 * xmlGzfileRead:
519 * @context: the I/O context
520 * @buffer: where to drop data
521 * @len: number of bytes to write
522 *
523 * Read @len bytes to @buffer from the compressed I/O channel.
524 *
525 * Returns the number of bytes written
526 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000527static int
Owen Taylor3473f882001-02-23 17:55:21 +0000528xmlGzfileRead (void * context, char * buffer, int len) {
529 return(gzread((gzFile) context, &buffer[0], len));
530}
531
532/**
533 * xmlGzfileWrite:
534 * @context: the I/O context
535 * @buffer: where to drop data
536 * @len: number of bytes to write
537 *
538 * Write @len bytes from @buffer to the compressed I/O channel.
539 *
540 * Returns the number of bytes written
541 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000542static int
Owen Taylor3473f882001-02-23 17:55:21 +0000543xmlGzfileWrite (void * context, const char * buffer, int len) {
544 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
545}
546
547/**
548 * xmlGzfileClose:
549 * @context: the I/O context
550 *
551 * Close a compressed I/O channel
552 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000553static int
Owen Taylor3473f882001-02-23 17:55:21 +0000554xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000555 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000556}
557#endif /* HAVE_ZLIB_H */
558
559#ifdef LIBXML_HTTP_ENABLED
560/************************************************************************
561 * *
562 * I/O for HTTP file accesses *
563 * *
564 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000565
566typedef struct xmlIOHTTPWriteCtxt_
567{
568 int compression;
569
570 char * uri;
571
572 void * doc_buff;
573
574} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
575
576#ifdef HAVE_ZLIB_H
577
578#define DFLT_WBITS ( -15 )
579#define DFLT_MEM_LVL ( 8 )
580#define GZ_MAGIC1 ( 0x1f )
581#define GZ_MAGIC2 ( 0x8b )
582#define LXML_ZLIB_OS_CODE ( 0x03 )
583#define INIT_HTTP_BUFF_SIZE ( 32768 )
584#define DFLT_ZLIB_RATIO ( 5 )
585
586/*
587** Data structure and functions to work with sending compressed data
588** via HTTP.
589*/
590
591typedef struct xmlZMemBuff_
592{
593 unsigned long size;
594 unsigned long crc;
595
596 unsigned char * zbuff;
597 z_stream zctrl;
598
599} xmlZMemBuff, *xmlZMemBuffPtr;
600
601/**
602 * append_reverse_ulong
603 * @buff: Compressed memory buffer
604 * @data: Unsigned long to append
605 *
606 * Append a unsigned long in reverse byte order to the end of the
607 * memory buffer.
608 */
609static void
610append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
611
612 int idx;
613
614 if ( buff == NULL )
615 return;
616
617 /*
618 ** This is plagiarized from putLong in gzio.c (zlib source) where
619 ** the number "4" is hardcoded. If zlib is ever patched to
620 ** support 64 bit file sizes, this code would need to be patched
621 ** as well.
622 */
623
624 for ( idx = 0; idx < 4; idx++ ) {
625 *buff->zctrl.next_out = ( data & 0xff );
626 data >>= 8;
627 buff->zctrl.next_out++;
628 }
629
630 return;
631}
632
633/**
634 *
635 * xmlFreeZMemBuff
636 * @buff: The memory buffer context to clear
637 *
638 * Release all the resources associated with the compressed memory buffer.
639 */
640static void
641xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
642
643 int z_err;
644
645 if ( buff == NULL )
646 return;
647
648 xmlFree( buff->zbuff );
649 z_err = deflateEnd( &buff->zctrl );
650#ifdef DEBUG_HTTP
651 if ( z_err != Z_OK )
652 xmlGenericError( xmlGenericErrorContext,
653 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
654 z_err );
655#endif
656
657 xmlFree( buff );
658 return;
659}
660
661/**
662 * xmlCreateZMemBuff
663 *@compression: Compression value to use
664 *
665 * Create a memory buffer to hold the compressed XML document. The
666 * compressed document in memory will end up being identical to what
667 * would be created if gzopen/gzwrite/gzclose were being used to
668 * write the document to disk. The code for the header/trailer data to
669 * the compression is plagiarized from the zlib source files.
670 */
671static void *
672xmlCreateZMemBuff( int compression ) {
673
674 int z_err;
675 int hdr_lgth;
676 xmlZMemBuffPtr buff = NULL;
677
678 if ( ( compression < 1 ) || ( compression > 9 ) )
679 return ( NULL );
680
681 /* Create the control and data areas */
682
683 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
684 if ( buff == NULL ) {
685 xmlGenericError( xmlGenericErrorContext,
686 "xmlCreateZMemBuff: %s\n",
687 "Failure allocating buffer context." );
688 return ( NULL );
689 }
690
691 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
692 buff->size = INIT_HTTP_BUFF_SIZE;
693 buff->zbuff = xmlMalloc( buff->size );
694 if ( buff->zbuff == NULL ) {
695 xmlFreeZMemBuff( buff );
696 xmlGenericError( xmlGenericErrorContext,
697 "xmlCreateZMemBuff: %s\n",
698 "Failure allocating data buffer." );
699 return ( NULL );
700 }
701
702 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
703 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
704 if ( z_err != Z_OK ) {
705 xmlFreeZMemBuff( buff );
706 buff = NULL;
707 xmlGenericError( xmlGenericErrorContext,
708 "xmlCreateZMemBuff: %s %d\n",
709 "Error initializing compression context. ZLIB error:",
710 z_err );
711 return ( NULL );
712 }
713
714 /* Set the header data. The CRC will be needed for the trailer */
715
716 buff->crc = crc32( 0L, Z_NULL, 0 );
717 hdr_lgth = sprintf( (char *)buff->zbuff, "%c%c%c%c%c%c%c%c%c%c",
718 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
719 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
720 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
721 buff->zctrl.avail_out = buff->size - hdr_lgth;
722
723 return ( buff );
724}
725
726/**
727 * xmlZMemBuffExtend
728 * @buff: Buffer used to compress and consolidate data.
729 * @ext_amt: Number of bytes to extend the buffer.
730 *
731 * Extend the internal buffer used to store the compressed data by the
732 * specified amount.
733 *
734 * Returns 0 on success or -1 on failure to extend the buffer. On failure
735 * the original buffer still exists at the original size.
736 */
737static int
738xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
739
740 int rc = -1;
741 size_t new_size;
742 size_t cur_used;
743
744 unsigned char * tmp_ptr = NULL;
745
746 if ( buff == NULL )
747 return ( -1 );
748
749 else if ( ext_amt == 0 )
750 return ( 0 );
751
752 cur_used = buff->zctrl.next_out - buff->zbuff;
753 new_size = buff->size + ext_amt;
754
755#ifdef DEBUG_HTTP
756 if ( cur_used > new_size )
757 xmlGenericError( xmlGenericErrorContext,
758 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
759 "Buffer overwrite detected during compressed memory",
760 "buffer extension. Overflowed by",
761 (cur_used - new_size ) );
762#endif
763
764 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
765 if ( tmp_ptr != NULL ) {
766 rc = 0;
767 buff->size = new_size;
768 buff->zbuff = tmp_ptr;
769 buff->zctrl.next_out = tmp_ptr + cur_used;
770 buff->zctrl.avail_out = new_size - cur_used;
771 }
772 else {
773 xmlGenericError( xmlGenericErrorContext,
774 "xmlZMemBuffExtend: %s %lu bytes.\n",
775 "Allocation failure extending output buffer to",
776 new_size );
777 }
778
779 return ( rc );
780}
781
782/**
783 * xmlZMemBuffAppend
784 * @buff: Buffer used to compress and consolidate data
785 * @src: Uncompressed source content to append to buffer
786 * @len: Length of source data to append to buffer
787 *
788 * Compress and append data to the internal buffer. The data buffer
789 * will be expanded if needed to store the additional data.
790 *
791 * Returns the number of bytes appended to the buffer or -1 on error.
792 */
793static int
794xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
795
796 int z_err;
797 size_t min_accept;
798
799 if ( ( buff == NULL ) || ( src == NULL ) )
800 return ( -1 );
801
802 buff->zctrl.avail_in = len;
803 buff->zctrl.next_in = (unsigned char *)src;
804 while ( buff->zctrl.avail_in > 0 ) {
805 /*
806 ** Extend the buffer prior to deflate call if a reasonable amount
807 ** of output buffer space is not available.
808 */
809 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
810 if ( buff->zctrl.avail_out <= min_accept ) {
811 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
812 return ( -1 );
813 }
814
815 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
816 if ( z_err != Z_OK ) {
817 xmlGenericError( xmlGenericErrorContext,
818 "xmlZMemBuffAppend: %s %d %s - %d",
819 "Compression error while appending",
820 len, "bytes to buffer. ZLIB error", z_err );
821 return ( -1 );
822 }
823 }
824
825 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
826
827 return ( len );
828}
829
830/**
831 * xmlZMemBuffGetContent
832 * @buff: Compressed memory content buffer
833 * @data_ref: Pointer reference to point to compressed content
834 *
835 * Flushes the compression buffers, appends gzip file trailers and
836 * returns the compressed content and length of the compressed data.
837 * NOTE: The gzip trailer code here is plagiarized from zlib source.
838 *
839 * Returns the length of the compressed data or -1 on error.
840 */
841static int
842xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
843
844 int zlgth = -1;
845 int z_err;
846
847 if ( ( buff == NULL ) || ( data_ref == NULL ) )
848 return ( -1 );
849
850 /* Need to loop until compression output buffers are flushed */
851
852 do
853 {
854 z_err = deflate( &buff->zctrl, Z_FINISH );
855 if ( z_err == Z_OK ) {
856 /* In this case Z_OK means more buffer space needed */
857
858 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
859 return ( -1 );
860 }
861 }
862 while ( z_err == Z_OK );
863
864 /* If the compression state is not Z_STREAM_END, some error occurred */
865
866 if ( z_err == Z_STREAM_END ) {
867
868 /* Need to append the gzip data trailer */
869
870 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
871 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
872 return ( -1 );
873 }
874
875 /*
876 ** For whatever reason, the CRC and length data are pushed out
877 ** in reverse byte order. So a memcpy can't be used here.
878 */
879
880 append_reverse_ulong( buff, buff->crc );
881 append_reverse_ulong( buff, buff->zctrl.total_in );
882
883 zlgth = buff->zctrl.next_out - buff->zbuff;
884 *data_ref = (char *)buff->zbuff;
885 }
886
887 else
888 xmlGenericError( xmlGenericErrorContext,
889 "xmlZMemBuffGetContent: %s - %d\n",
890 "Error flushing zlib buffers. Error code", z_err );
891
892 return ( zlgth );
893}
894#endif /* HAVE_ZLIB_H */
895
896/**
897 * xmlFreeHTTPWriteCtxt
898 * @ctxt: Context to cleanup
899 *
900 * Free allocated memory and reclaim system resources.
901 *
902 * No return value.
903 */
904static void
905xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
906{
907 if ( ctxt->uri != NULL )
908 free( ctxt->uri );
909
910 if ( ctxt->doc_buff != NULL ) {
911
912#ifdef HAVE_ZLIB_H
913 if ( ctxt->compression > 0 ) {
914 xmlFreeZMemBuff( ctxt->doc_buff );
915 }
916 else
917#endif
918 {
919 xmlOutputBufferClose( ctxt->doc_buff );
920 }
921 }
922
923 free( ctxt );
924 return;
925}
926
927
Owen Taylor3473f882001-02-23 17:55:21 +0000928/**
929 * xmlIOHTTPMatch:
930 * @filename: the URI for matching
931 *
932 * check if the URI matches an HTTP one
933 *
934 * Returns 1 if matches, 0 otherwise
935 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000936int
Owen Taylor3473f882001-02-23 17:55:21 +0000937xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000938 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +0000939 return(1);
940 return(0);
941}
942
943/**
944 * xmlIOHTTPOpen:
945 * @filename: the URI for matching
946 *
947 * open an HTTP I/O channel
948 *
949 * Returns an I/O context or NULL in case of error
950 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000951void *
Owen Taylor3473f882001-02-23 17:55:21 +0000952xmlIOHTTPOpen (const char *filename) {
953 return(xmlNanoHTTPOpen(filename, NULL));
954}
955
956/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000957 * xmlIOHTTPOpenW
958 * @post_uri: The destination URI for the document
959 * @compression: The compression desired for the document.
960 *
961 * Open a temporary buffer to collect the document for a subsequent HTTP POST
962 * request. Non-static as is called from the output buffer creation routine.
963 *
964 * Returns an I/O context or NULL in case of error.
965 */
966
967void *
Daniel Veillard572577e2002-01-18 16:23:55 +0000968xmlIOHTTPOpenW(const char *post_uri, int compression)
969{
Daniel Veillardf012a642001-07-23 19:10:52 +0000970
Daniel Veillard572577e2002-01-18 16:23:55 +0000971 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +0000972
Daniel Veillard572577e2002-01-18 16:23:55 +0000973 if (post_uri == NULL)
974 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000975
Daniel Veillard572577e2002-01-18 16:23:55 +0000976 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
977 if (ctxt == NULL) {
978 xmlGenericError(xmlGenericErrorContext,
979 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
980 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000981 }
982
Daniel Veillard572577e2002-01-18 16:23:55 +0000983 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +0000984
Daniel Veillard572577e2002-01-18 16:23:55 +0000985 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
986 if (ctxt->uri == NULL) {
987 xmlGenericError(xmlGenericErrorContext,
988 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
989 xmlFreeHTTPWriteCtxt(ctxt);
990 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000991 }
992
993 /*
Daniel Veillard572577e2002-01-18 16:23:55 +0000994 * ** Since the document length is required for an HTTP post,
995 * ** need to put the document into a buffer. A memory buffer
996 * ** is being used to avoid pushing the data to disk and back.
997 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000998
999#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001000 if ((compression > 0) && (compression <= 9)) {
1001
1002 ctxt->compression = compression;
1003 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1004 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001005#endif
1006 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001007 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001008
Daniel Veillard572577e2002-01-18 16:23:55 +00001009 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001010 }
1011
Daniel Veillard572577e2002-01-18 16:23:55 +00001012 if (ctxt->doc_buff == NULL) {
1013 xmlFreeHTTPWriteCtxt(ctxt);
1014 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001015 }
1016
Daniel Veillard572577e2002-01-18 16:23:55 +00001017 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001018}
1019
1020/**
1021 * xmlIOHTTPDfltOpenW
1022 * @post_uri: The destination URI for this document.
1023 *
1024 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1025 * HTTP post command. This function should generally not be used as
1026 * the open callback is short circuited in xmlOutputBufferCreateFile.
1027 *
1028 * Returns a pointer to the new IO context.
1029 */
1030static void *
1031xmlIOHTTPDfltOpenW( const char * post_uri ) {
1032 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1033}
1034
1035/**
Owen Taylor3473f882001-02-23 17:55:21 +00001036 * xmlIOHTTPRead:
1037 * @context: the I/O context
1038 * @buffer: where to drop data
1039 * @len: number of bytes to write
1040 *
1041 * Read @len bytes to @buffer from the I/O channel.
1042 *
1043 * Returns the number of bytes written
1044 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001045int
Owen Taylor3473f882001-02-23 17:55:21 +00001046xmlIOHTTPRead(void * context, char * buffer, int len) {
1047 return(xmlNanoHTTPRead(context, &buffer[0], len));
1048}
1049
1050/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001051 * xmlIOHTTPWrite
1052 * @context: previously opened writing context
1053 * @buffer: data to output to temporary buffer
1054 * @len: bytes to output
1055 *
1056 * Collect data from memory buffer into a temporary file for later
1057 * processing.
1058 *
1059 * Returns number of bytes written.
1060 */
1061
1062static int
1063xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1064
1065 xmlIOHTTPWriteCtxtPtr ctxt = context;
1066
1067 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1068 return ( -1 );
1069
1070 if ( len > 0 ) {
1071
1072 /* Use gzwrite or fwrite as previously setup in the open call */
1073
1074#ifdef HAVE_ZLIB_H
1075 if ( ctxt->compression > 0 )
1076 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1077
1078 else
1079#endif
1080 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1081
1082 if ( len < 0 ) {
1083 xmlGenericError( xmlGenericErrorContext,
1084 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1085 "Error appending to internal buffer.",
1086 "Error sending document to URI",
1087 ctxt->uri );
1088 }
1089 }
1090
1091 return ( len );
1092}
1093
1094
1095/**
Owen Taylor3473f882001-02-23 17:55:21 +00001096 * xmlIOHTTPClose:
1097 * @context: the I/O context
1098 *
1099 * Close an HTTP I/O channel
1100 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001101int
Owen Taylor3473f882001-02-23 17:55:21 +00001102xmlIOHTTPClose (void * context) {
1103 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001104 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001105}
Daniel Veillardf012a642001-07-23 19:10:52 +00001106
1107/**
1108 * xmlIOHTTCloseWrite
1109 * @context: The I/O context
1110 * @http_mthd: The HTTP method to be used when sending the data
1111 *
1112 * Close the transmit HTTP I/O channel and actually send the data.
1113 */
1114static int
1115xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1116
1117 int close_rc = -1;
1118 int http_rtn = 0;
1119 int content_lgth = 0;
1120 xmlIOHTTPWriteCtxtPtr ctxt = context;
1121
1122 char * http_content = NULL;
1123 char * content_encoding = NULL;
1124 char * content_type = (char *) "text/xml";
1125 void * http_ctxt = NULL;
1126
1127 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1128 return ( -1 );
1129
1130 /* Retrieve the content from the appropriate buffer */
1131
1132#ifdef HAVE_ZLIB_H
1133
1134 if ( ctxt->compression > 0 ) {
1135 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1136 content_encoding = (char *) "Content-Encoding: gzip";
1137 }
1138 else
1139#endif
1140 {
1141 /* Pull the data out of the memory output buffer */
1142
1143 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1144 http_content = (char *)dctxt->buffer->content;
1145 content_lgth = dctxt->buffer->use;
1146 }
1147
1148 if ( http_content == NULL ) {
1149 xmlGenericError( xmlGenericErrorContext,
1150 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1151 "Error retrieving content.\nUnable to",
1152 http_mthd, "data to URI", ctxt->uri );
1153 }
1154
1155 else {
1156
1157 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1158 &content_type, content_encoding,
1159 content_lgth );
1160
1161 if ( http_ctxt != NULL ) {
1162#ifdef DEBUG_HTTP
1163 /* If testing/debugging - dump reply with request content */
1164
1165 FILE * tst_file = NULL;
1166 char buffer[ 4096 ];
1167 char * dump_name = NULL;
1168 int avail;
1169
1170 xmlGenericError( xmlGenericErrorContext,
1171 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1172 http_mthd, ctxt->uri,
1173 xmlNanoHTTPReturnCode( http_ctxt ) );
1174
1175 /*
1176 ** Since either content or reply may be gzipped,
1177 ** dump them to separate files instead of the
1178 ** standard error context.
1179 */
1180
1181 dump_name = tempnam( NULL, "lxml" );
1182 if ( dump_name != NULL ) {
1183 (void)sprintf( buffer, "%s.content", dump_name );
1184
1185 tst_file = fopen( buffer, "w" );
1186 if ( tst_file != NULL ) {
1187 xmlGenericError( xmlGenericErrorContext,
1188 "Transmitted content saved in file: %s\n", buffer );
1189
1190 fwrite( http_content, sizeof( char ),
1191 content_lgth, tst_file );
1192 fclose( tst_file );
1193 }
1194
1195 (void)sprintf( buffer, "%s.reply", dump_name );
1196 tst_file = fopen( buffer, "w" );
1197 if ( tst_file != NULL ) {
1198 xmlGenericError( xmlGenericErrorContext,
1199 "Reply content saved in file: %s\n", buffer );
1200
1201
1202 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1203 buffer, sizeof( buffer ) )) > 0 ) {
1204
1205 fwrite( buffer, sizeof( char ), avail, tst_file );
1206 }
1207
1208 fclose( tst_file );
1209 }
1210
1211 free( dump_name );
1212 }
1213#endif /* DEBUG_HTTP */
1214
1215 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1216 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1217 close_rc = 0;
1218 else
1219 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001220 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001221 http_mthd, content_lgth,
1222 "bytes to URI", ctxt->uri,
1223 "failed. HTTP return code:", http_rtn );
1224
1225 xmlNanoHTTPClose( http_ctxt );
1226 xmlFree( content_type );
1227 }
1228 }
1229
1230 /* Final cleanups */
1231
1232 xmlFreeHTTPWriteCtxt( ctxt );
1233
1234 return ( close_rc );
1235}
1236
1237/**
1238 * xmlIOHTTPClosePut
1239 *
1240 * @context: The I/O context
1241 *
1242 * Close the transmit HTTP I/O channel and actually send data using a PUT
1243 * HTTP method.
1244 */
1245static int
1246xmlIOHTTPClosePut( void * ctxt ) {
1247 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1248}
1249
1250
1251/**
1252 * xmlIOHTTPClosePost
1253 *
1254 * @context: The I/O context
1255 *
1256 * Close the transmit HTTP I/O channel and actually send data using a POST
1257 * HTTP method.
1258 */
1259static int
1260xmlIOHTTPClosePost( void * ctxt ) {
1261 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1262}
1263
Owen Taylor3473f882001-02-23 17:55:21 +00001264#endif /* LIBXML_HTTP_ENABLED */
1265
1266#ifdef LIBXML_FTP_ENABLED
1267/************************************************************************
1268 * *
1269 * I/O for FTP file accesses *
1270 * *
1271 ************************************************************************/
1272/**
1273 * xmlIOFTPMatch:
1274 * @filename: the URI for matching
1275 *
1276 * check if the URI matches an FTP one
1277 *
1278 * Returns 1 if matches, 0 otherwise
1279 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001280int
Owen Taylor3473f882001-02-23 17:55:21 +00001281xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001282 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001283 return(1);
1284 return(0);
1285}
1286
1287/**
1288 * xmlIOFTPOpen:
1289 * @filename: the URI for matching
1290 *
1291 * open an FTP I/O channel
1292 *
1293 * Returns an I/O context or NULL in case of error
1294 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001295void *
Owen Taylor3473f882001-02-23 17:55:21 +00001296xmlIOFTPOpen (const char *filename) {
1297 return(xmlNanoFTPOpen(filename));
1298}
1299
1300/**
1301 * xmlIOFTPRead:
1302 * @context: the I/O context
1303 * @buffer: where to drop data
1304 * @len: number of bytes to write
1305 *
1306 * Read @len bytes to @buffer from the I/O channel.
1307 *
1308 * Returns the number of bytes written
1309 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001310int
Owen Taylor3473f882001-02-23 17:55:21 +00001311xmlIOFTPRead(void * context, char * buffer, int len) {
1312 return(xmlNanoFTPRead(context, &buffer[0], len));
1313}
1314
1315/**
1316 * xmlIOFTPClose:
1317 * @context: the I/O context
1318 *
1319 * Close an FTP I/O channel
1320 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001321int
Owen Taylor3473f882001-02-23 17:55:21 +00001322xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001323 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001324}
1325#endif /* LIBXML_FTP_ENABLED */
1326
1327
1328/**
1329 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001330 * @matchFunc: the xmlInputMatchCallback
1331 * @openFunc: the xmlInputOpenCallback
1332 * @readFunc: the xmlInputReadCallback
1333 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001334 *
1335 * Register a new set of I/O callback for handling parser input.
1336 *
1337 * Returns the registered handler number or -1 in case of error
1338 */
1339int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001340xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1341 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1342 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001343 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1344 return(-1);
1345 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001346 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1347 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1348 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1349 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001350 return(xmlInputCallbackNr++);
1351}
1352
1353/**
1354 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001355 * @matchFunc: the xmlOutputMatchCallback
1356 * @openFunc: the xmlOutputOpenCallback
1357 * @writeFunc: the xmlOutputWriteCallback
1358 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001359 *
1360 * Register a new set of I/O callback for handling output.
1361 *
1362 * Returns the registered handler number or -1 in case of error
1363 */
1364int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001365xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1366 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1367 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001368 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1369 return(-1);
1370 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001371 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1372 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1373 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1374 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001375 return(xmlOutputCallbackNr++);
1376}
1377
1378/**
1379 * xmlRegisterDefaultInputCallbacks:
1380 *
1381 * Registers the default compiled-in I/O handlers.
1382 */
1383void
1384#ifdef VMS
1385xmlRegisterDefInputCallbacks
1386#else
1387xmlRegisterDefaultInputCallbacks
1388#endif
1389(void) {
1390 if (xmlInputCallbackInitialized)
1391 return;
1392
1393 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1394 xmlFileRead, xmlFileClose);
1395#ifdef HAVE_ZLIB_H
1396 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1397 xmlGzfileRead, xmlGzfileClose);
1398#endif /* HAVE_ZLIB_H */
1399
1400#ifdef LIBXML_HTTP_ENABLED
1401 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1402 xmlIOHTTPRead, xmlIOHTTPClose);
1403#endif /* LIBXML_HTTP_ENABLED */
1404
1405#ifdef LIBXML_FTP_ENABLED
1406 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1407 xmlIOFTPRead, xmlIOFTPClose);
1408#endif /* LIBXML_FTP_ENABLED */
1409 xmlInputCallbackInitialized = 1;
1410}
1411
1412/**
1413 * xmlRegisterDefaultOutputCallbacks:
1414 *
1415 * Registers the default compiled-in I/O handlers.
1416 */
1417void
1418#ifdef VMS
1419xmlRegisterDefOutputCallbacks
1420#else
1421xmlRegisterDefaultOutputCallbacks
1422#endif
1423(void) {
1424 if (xmlOutputCallbackInitialized)
1425 return;
1426
1427 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1428 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001429
1430#ifdef LIBXML_HTTP_ENABLED
1431 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1432 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1433#endif
1434
Owen Taylor3473f882001-02-23 17:55:21 +00001435/*********************************
1436 No way a-priori to distinguish between gzipped files from
1437 uncompressed ones except opening if existing then closing
1438 and saving with same compression ratio ... a pain.
1439
1440#ifdef HAVE_ZLIB_H
1441 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1442 xmlGzfileWrite, xmlGzfileClose);
1443#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001444
1445 Nor FTP PUT ....
1446#ifdef LIBXML_FTP_ENABLED
1447 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1448 xmlIOFTPWrite, xmlIOFTPClose);
1449#endif
1450 **********************************/
1451 xmlOutputCallbackInitialized = 1;
1452}
1453
Daniel Veillardf012a642001-07-23 19:10:52 +00001454#ifdef LIBXML_HTTP_ENABLED
1455/**
1456 * xmlRegisterHTTPPostCallbacks
1457 *
1458 * By default, libxml submits HTTP output requests using the "PUT" method.
1459 * Calling this method changes the HTTP output method to use the "POST"
1460 * method instead.
1461 *
1462 */
1463void
1464xmlRegisterHTTPPostCallbacks( void ) {
1465
1466 /* Register defaults if not done previously */
1467
1468 if ( xmlOutputCallbackInitialized == 0 )
1469 xmlRegisterDefaultOutputCallbacks( );
1470
1471 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1472 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1473 return;
1474}
1475#endif
1476
Owen Taylor3473f882001-02-23 17:55:21 +00001477/**
1478 * xmlAllocParserInputBuffer:
1479 * @enc: the charset encoding if known
1480 *
1481 * Create a buffered parser input for progressive parsing
1482 *
1483 * Returns the new parser input or NULL
1484 */
1485xmlParserInputBufferPtr
1486xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1487 xmlParserInputBufferPtr ret;
1488
1489 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1490 if (ret == NULL) {
1491 xmlGenericError(xmlGenericErrorContext,
1492 "xmlAllocParserInputBuffer : out of memory!\n");
1493 return(NULL);
1494 }
1495 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1496 ret->buffer = xmlBufferCreate();
1497 if (ret->buffer == NULL) {
1498 xmlFree(ret);
1499 return(NULL);
1500 }
1501 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1502 ret->encoder = xmlGetCharEncodingHandler(enc);
1503 if (ret->encoder != NULL)
1504 ret->raw = xmlBufferCreate();
1505 else
1506 ret->raw = NULL;
1507 ret->readcallback = NULL;
1508 ret->closecallback = NULL;
1509 ret->context = NULL;
1510
1511 return(ret);
1512}
1513
1514/**
1515 * xmlAllocOutputBuffer:
1516 * @encoder: the encoding converter or NULL
1517 *
1518 * Create a buffered parser output
1519 *
1520 * Returns the new parser output or NULL
1521 */
1522xmlOutputBufferPtr
1523xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1524 xmlOutputBufferPtr ret;
1525
1526 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1527 if (ret == NULL) {
1528 xmlGenericError(xmlGenericErrorContext,
1529 "xmlAllocOutputBuffer : out of memory!\n");
1530 return(NULL);
1531 }
1532 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1533 ret->buffer = xmlBufferCreate();
1534 if (ret->buffer == NULL) {
1535 xmlFree(ret);
1536 return(NULL);
1537 }
1538 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1539 ret->encoder = encoder;
1540 if (encoder != NULL) {
1541 ret->conv = xmlBufferCreateSize(4000);
1542 /*
1543 * This call is designed to initiate the encoder state
1544 */
1545 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1546 } else
1547 ret->conv = NULL;
1548 ret->writecallback = NULL;
1549 ret->closecallback = NULL;
1550 ret->context = NULL;
1551 ret->written = 0;
1552
1553 return(ret);
1554}
1555
1556/**
1557 * xmlFreeParserInputBuffer:
1558 * @in: a buffered parser input
1559 *
1560 * Free up the memory used by a buffered parser input
1561 */
1562void
1563xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1564 if (in->raw) {
1565 xmlBufferFree(in->raw);
1566 in->raw = NULL;
1567 }
1568 if (in->encoder != NULL) {
1569 xmlCharEncCloseFunc(in->encoder);
1570 }
1571 if (in->closecallback != NULL) {
1572 in->closecallback(in->context);
1573 }
1574 if (in->buffer != NULL) {
1575 xmlBufferFree(in->buffer);
1576 in->buffer = NULL;
1577 }
1578
Owen Taylor3473f882001-02-23 17:55:21 +00001579 xmlFree(in);
1580}
1581
1582/**
1583 * xmlOutputBufferClose:
1584 * @out: a buffered output
1585 *
1586 * flushes and close the output I/O channel
1587 * and free up all the associated resources
1588 *
1589 * Returns the number of byte written or -1 in case of error.
1590 */
1591int
1592xmlOutputBufferClose(xmlOutputBufferPtr out) {
1593 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001594 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001595
1596 if (out == NULL)
1597 return(-1);
1598 if (out->writecallback != NULL)
1599 xmlOutputBufferFlush(out);
1600 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001601 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001602 }
1603 written = out->written;
1604 if (out->conv) {
1605 xmlBufferFree(out->conv);
1606 out->conv = NULL;
1607 }
1608 if (out->encoder != NULL) {
1609 xmlCharEncCloseFunc(out->encoder);
1610 }
1611 if (out->buffer != NULL) {
1612 xmlBufferFree(out->buffer);
1613 out->buffer = NULL;
1614 }
1615
Owen Taylor3473f882001-02-23 17:55:21 +00001616 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001617 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001618}
1619
1620/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001621 * xmlParserInputBufferCreateFname:
1622 * @URI: a C string containing the URI or filename
1623 * @enc: the charset encoding if known
1624 *
1625 * VMS version of xmlParserInputBufferCreateFilename()
1626 *
1627 * Returns the new parser input or NULL
1628 */
1629/**
Owen Taylor3473f882001-02-23 17:55:21 +00001630 * xmlParserInputBufferCreateFilename:
1631 * @URI: a C string containing the URI or filename
1632 * @enc: the charset encoding if known
1633 *
1634 * Create a buffered parser input for the progressive parsing of a file
1635 * If filename is "-' then we use stdin as the input.
1636 * Automatic support for ZLIB/Compress compressed document is provided
1637 * by default if found at compile-time.
1638 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1639 *
1640 * Returns the new parser input or NULL
1641 */
1642xmlParserInputBufferPtr
1643#ifdef VMS
1644xmlParserInputBufferCreateFname
1645#else
1646xmlParserInputBufferCreateFilename
1647#endif
1648(const char *URI, xmlCharEncoding enc) {
1649 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001650 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001651 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001652 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001653
1654 if (xmlInputCallbackInitialized == 0)
1655 xmlRegisterDefaultInputCallbacks();
1656
1657 if (URI == NULL) return(NULL);
1658
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001659#ifdef LIBXML_CATALOG_ENABLED
1660#endif
1661
Owen Taylor3473f882001-02-23 17:55:21 +00001662 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001663 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001664 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001665 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001666 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001667 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1668 if (unescaped != NULL) {
1669 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1670 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1671 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1672 context = xmlInputCallbackTable[i].opencallback(unescaped);
1673 if (context != NULL)
1674 break;
1675 }
1676 }
1677 xmlFree(unescaped);
1678 }
1679
1680 /*
1681 * If this failed try with a non-escaped URI this may be a strange
1682 * filename
1683 */
1684 if (context == NULL) {
1685 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1686 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1687 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1688 context = xmlInputCallbackTable[i].opencallback(URI);
1689 if (context != NULL)
1690 break;
1691 }
Owen Taylor3473f882001-02-23 17:55:21 +00001692 }
1693 }
1694 if (context == NULL) {
1695 return(NULL);
1696 }
1697
1698 /*
1699 * Allocate the Input buffer front-end.
1700 */
1701 ret = xmlAllocParserInputBuffer(enc);
1702 if (ret != NULL) {
1703 ret->context = context;
1704 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1705 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1706 }
1707 return(ret);
1708}
1709
1710/**
1711 * xmlOutputBufferCreateFilename:
1712 * @URI: a C string containing the URI or filename
1713 * @encoder: the encoding converter or NULL
1714 * @compression: the compression ration (0 none, 9 max).
1715 *
1716 * Create a buffered output for the progressive saving of a file
1717 * If filename is "-' then we use stdout as the output.
1718 * Automatic support for ZLIB/Compress compressed document is provided
1719 * by default if found at compile-time.
1720 * TODO: currently if compression is set, the library only support
1721 * writing to a local file.
1722 *
1723 * Returns the new output or NULL
1724 */
1725xmlOutputBufferPtr
1726xmlOutputBufferCreateFilename(const char *URI,
1727 xmlCharEncodingHandlerPtr encoder,
1728 int compression) {
1729 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001730 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001731 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001732 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001733
Daniel Veillardf012a642001-07-23 19:10:52 +00001734 int is_http_uri = 0; /* Can't change if HTTP disabled */
1735
Owen Taylor3473f882001-02-23 17:55:21 +00001736 if (xmlOutputCallbackInitialized == 0)
1737 xmlRegisterDefaultOutputCallbacks();
1738
1739 if (URI == NULL) return(NULL);
1740
Daniel Veillardf012a642001-07-23 19:10:52 +00001741#ifdef LIBXML_HTTP_ENABLED
1742 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1743
1744 is_http_uri = xmlIOHTTPMatch( URI );
1745#endif
1746
Owen Taylor3473f882001-02-23 17:55:21 +00001747
1748 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001749 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001750 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001751 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001752 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001753 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1754 if (unescaped != NULL) {
1755#ifdef HAVE_ZLIB_H
1756 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1757 context = xmlGzfileOpenW(unescaped, compression);
1758 if (context != NULL) {
1759 ret = xmlAllocOutputBuffer(encoder);
1760 if (ret != NULL) {
1761 ret->context = context;
1762 ret->writecallback = xmlGzfileWrite;
1763 ret->closecallback = xmlGzfileClose;
1764 }
1765 xmlFree(unescaped);
1766 return(ret);
1767 }
1768 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001769#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001770 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1771 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1772 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1773#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1774 /* Need to pass compression parameter into HTTP open calls */
1775 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1776 context = xmlIOHTTPOpenW(unescaped, compression);
1777 else
1778#endif
1779 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1780 if (context != NULL)
1781 break;
1782 }
1783 }
1784 xmlFree(unescaped);
1785 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001786
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001787 /*
1788 * If this failed try with a non-escaped URI this may be a strange
1789 * filename
1790 */
1791 if (context == NULL) {
1792#ifdef HAVE_ZLIB_H
1793 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1794 context = xmlGzfileOpenW(URI, compression);
1795 if (context != NULL) {
1796 ret = xmlAllocOutputBuffer(encoder);
1797 if (ret != NULL) {
1798 ret->context = context;
1799 ret->writecallback = xmlGzfileWrite;
1800 ret->closecallback = xmlGzfileClose;
1801 }
1802 return(ret);
1803 }
1804 }
1805#endif
1806 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1807 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1808 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001809#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1810 /* Need to pass compression parameter into HTTP open calls */
1811 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1812 context = xmlIOHTTPOpenW(URI, compression);
1813 else
1814#endif
1815 context = xmlOutputCallbackTable[i].opencallback(URI);
1816 if (context != NULL)
1817 break;
1818 }
Owen Taylor3473f882001-02-23 17:55:21 +00001819 }
1820 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001821
Owen Taylor3473f882001-02-23 17:55:21 +00001822 if (context == NULL) {
1823 return(NULL);
1824 }
1825
1826 /*
1827 * Allocate the Output buffer front-end.
1828 */
1829 ret = xmlAllocOutputBuffer(encoder);
1830 if (ret != NULL) {
1831 ret->context = context;
1832 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1833 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1834 }
1835 return(ret);
1836}
1837
1838/**
1839 * xmlParserInputBufferCreateFile:
1840 * @file: a FILE*
1841 * @enc: the charset encoding if known
1842 *
1843 * Create a buffered parser input for the progressive parsing of a FILE *
1844 * buffered C I/O
1845 *
1846 * Returns the new parser input or NULL
1847 */
1848xmlParserInputBufferPtr
1849xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1850 xmlParserInputBufferPtr ret;
1851
1852 if (xmlInputCallbackInitialized == 0)
1853 xmlRegisterDefaultInputCallbacks();
1854
1855 if (file == NULL) return(NULL);
1856
1857 ret = xmlAllocParserInputBuffer(enc);
1858 if (ret != NULL) {
1859 ret->context = file;
1860 ret->readcallback = xmlFileRead;
1861 ret->closecallback = xmlFileFlush;
1862 }
1863
1864 return(ret);
1865}
1866
1867/**
1868 * xmlOutputBufferCreateFile:
1869 * @file: a FILE*
1870 * @encoder: the encoding converter or NULL
1871 *
1872 * Create a buffered output for the progressive saving to a FILE *
1873 * buffered C I/O
1874 *
1875 * Returns the new parser output or NULL
1876 */
1877xmlOutputBufferPtr
1878xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1879 xmlOutputBufferPtr ret;
1880
1881 if (xmlOutputCallbackInitialized == 0)
1882 xmlRegisterDefaultOutputCallbacks();
1883
1884 if (file == NULL) return(NULL);
1885
1886 ret = xmlAllocOutputBuffer(encoder);
1887 if (ret != NULL) {
1888 ret->context = file;
1889 ret->writecallback = xmlFileWrite;
1890 ret->closecallback = xmlFileFlush;
1891 }
1892
1893 return(ret);
1894}
1895
1896/**
1897 * xmlParserInputBufferCreateFd:
1898 * @fd: a file descriptor number
1899 * @enc: the charset encoding if known
1900 *
1901 * Create a buffered parser input for the progressive parsing for the input
1902 * from a file descriptor
1903 *
1904 * Returns the new parser input or NULL
1905 */
1906xmlParserInputBufferPtr
1907xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1908 xmlParserInputBufferPtr ret;
1909
1910 if (fd < 0) return(NULL);
1911
1912 ret = xmlAllocParserInputBuffer(enc);
1913 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001914 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001915 ret->readcallback = xmlFdRead;
1916 ret->closecallback = xmlFdClose;
1917 }
1918
1919 return(ret);
1920}
1921
1922/**
1923 * xmlParserInputBufferCreateMem:
1924 * @mem: the memory input
1925 * @size: the length of the memory block
1926 * @enc: the charset encoding if known
1927 *
1928 * Create a buffered parser input for the progressive parsing for the input
1929 * from a memory area.
1930 *
1931 * Returns the new parser input or NULL
1932 */
1933xmlParserInputBufferPtr
1934xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1935 xmlParserInputBufferPtr ret;
1936
1937 if (size <= 0) return(NULL);
1938 if (mem == NULL) return(NULL);
1939
1940 ret = xmlAllocParserInputBuffer(enc);
1941 if (ret != NULL) {
1942 ret->context = (void *) mem;
1943 ret->readcallback = (xmlInputReadCallback) xmlNop;
1944 ret->closecallback = NULL;
1945 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1946 }
1947
1948 return(ret);
1949}
1950
1951/**
1952 * xmlOutputBufferCreateFd:
1953 * @fd: a file descriptor number
1954 * @encoder: the encoding converter or NULL
1955 *
1956 * Create a buffered output for the progressive saving
1957 * to a file descriptor
1958 *
1959 * Returns the new parser output or NULL
1960 */
1961xmlOutputBufferPtr
1962xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1963 xmlOutputBufferPtr ret;
1964
1965 if (fd < 0) return(NULL);
1966
1967 ret = xmlAllocOutputBuffer(encoder);
1968 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001969 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001970 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00001971 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001972 }
1973
1974 return(ret);
1975}
1976
1977/**
1978 * xmlParserInputBufferCreateIO:
1979 * @ioread: an I/O read function
1980 * @ioclose: an I/O close function
1981 * @ioctx: an I/O handler
1982 * @enc: the charset encoding if known
1983 *
1984 * Create a buffered parser input for the progressive parsing for the input
1985 * from an I/O handler
1986 *
1987 * Returns the new parser input or NULL
1988 */
1989xmlParserInputBufferPtr
1990xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1991 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1992 xmlParserInputBufferPtr ret;
1993
1994 if (ioread == NULL) return(NULL);
1995
1996 ret = xmlAllocParserInputBuffer(enc);
1997 if (ret != NULL) {
1998 ret->context = (void *) ioctx;
1999 ret->readcallback = ioread;
2000 ret->closecallback = ioclose;
2001 }
2002
2003 return(ret);
2004}
2005
2006/**
2007 * xmlOutputBufferCreateIO:
2008 * @iowrite: an I/O write function
2009 * @ioclose: an I/O close function
2010 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002011 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002012 *
2013 * Create a buffered output for the progressive saving
2014 * to an I/O handler
2015 *
2016 * Returns the new parser output or NULL
2017 */
2018xmlOutputBufferPtr
2019xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2020 xmlOutputCloseCallback ioclose, void *ioctx,
2021 xmlCharEncodingHandlerPtr encoder) {
2022 xmlOutputBufferPtr ret;
2023
2024 if (iowrite == NULL) return(NULL);
2025
2026 ret = xmlAllocOutputBuffer(encoder);
2027 if (ret != NULL) {
2028 ret->context = (void *) ioctx;
2029 ret->writecallback = iowrite;
2030 ret->closecallback = ioclose;
2031 }
2032
2033 return(ret);
2034}
2035
2036/**
2037 * xmlParserInputBufferPush:
2038 * @in: a buffered parser input
2039 * @len: the size in bytes of the array.
2040 * @buf: an char array
2041 *
2042 * Push the content of the arry in the input buffer
2043 * This routine handle the I18N transcoding to internal UTF-8
2044 * This is used when operating the parser in progressive (push) mode.
2045 *
2046 * Returns the number of chars read and stored in the buffer, or -1
2047 * in case of error.
2048 */
2049int
2050xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2051 int len, const char *buf) {
2052 int nbchars = 0;
2053
2054 if (len < 0) return(0);
2055 if (in->encoder != NULL) {
2056 /*
2057 * Store the data in the incoming raw buffer
2058 */
2059 if (in->raw == NULL) {
2060 in->raw = xmlBufferCreate();
2061 }
2062 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2063
2064 /*
2065 * convert as much as possible to the parser reading buffer.
2066 */
2067 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2068 if (nbchars < 0) {
2069 xmlGenericError(xmlGenericErrorContext,
2070 "xmlParserInputBufferPush: encoder error\n");
2071 return(-1);
2072 }
2073 } else {
2074 nbchars = len;
2075 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2076 }
2077#ifdef DEBUG_INPUT
2078 xmlGenericError(xmlGenericErrorContext,
2079 "I/O: pushed %d chars, buffer %d/%d\n",
2080 nbchars, in->buffer->use, in->buffer->size);
2081#endif
2082 return(nbchars);
2083}
2084
2085/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002086 * endOfInput:
2087 *
2088 * When reading from an Input channel indicated end of file or error
2089 * don't reread from it again.
2090 */
2091static int
2092endOfInput (void * context ATTRIBUTE_UNUSED,
2093 char * buffer ATTRIBUTE_UNUSED,
2094 int len ATTRIBUTE_UNUSED) {
2095 return(0);
2096}
2097
2098/**
Owen Taylor3473f882001-02-23 17:55:21 +00002099 * xmlParserInputBufferGrow:
2100 * @in: a buffered parser input
2101 * @len: indicative value of the amount of chars to read
2102 *
2103 * Grow up the content of the input buffer, the old data are preserved
2104 * This routine handle the I18N transcoding to internal UTF-8
2105 * This routine is used when operating the parser in normal (pull) mode
2106 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002107 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002108 * onto in->buffer or in->raw
2109 *
2110 * Returns the number of chars read and stored in the buffer, or -1
2111 * in case of error.
2112 */
2113int
2114xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2115 char *buffer = NULL;
2116 int res = 0;
2117 int nbchars = 0;
2118 int buffree;
Daniel Veillarde5354492002-05-16 08:43:22 +00002119 int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002120
2121 if ((len <= MINLEN) && (len != 4))
2122 len = MINLEN;
2123 buffree = in->buffer->size - in->buffer->use;
2124 if (buffree <= 0) {
2125 xmlGenericError(xmlGenericErrorContext,
2126 "xmlParserInputBufferGrow : buffer full !\n");
2127 return(0);
2128 }
2129 if (len > buffree)
2130 len = buffree;
2131
Daniel Veillarde5354492002-05-16 08:43:22 +00002132 needSize = in->buffer->use + len + 1;
2133 if (needSize > in->buffer->size){
2134 if (!xmlBufferResize(in->buffer, needSize)){
2135 xmlGenericError(xmlGenericErrorContext,
2136 "xmlBufferAdd : out of memory!\n");
2137 return(0);
2138 }
Owen Taylor3473f882001-02-23 17:55:21 +00002139 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002140 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002141
2142 /*
2143 * Call the read method for this I/O type.
2144 */
2145 if (in->readcallback != NULL) {
2146 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002147 if (res <= 0)
2148 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002149 } else {
2150 xmlGenericError(xmlGenericErrorContext,
2151 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002152 return(-1);
2153 }
2154 if (res < 0) {
2155 perror ("read error");
Owen Taylor3473f882001-02-23 17:55:21 +00002156 return(-1);
2157 }
2158 len = res;
2159 if (in->encoder != NULL) {
2160 /*
2161 * Store the data in the incoming raw buffer
2162 */
2163 if (in->raw == NULL) {
2164 in->raw = xmlBufferCreate();
2165 }
2166 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2167
2168 /*
2169 * convert as much as possible to the parser reading buffer.
2170 */
2171 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2172 if (nbchars < 0) {
2173 xmlGenericError(xmlGenericErrorContext,
2174 "xmlParserInputBufferGrow: encoder error\n");
2175 return(-1);
2176 }
2177 } else {
2178 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002179 in->buffer->use += nbchars;
2180 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002181 }
2182#ifdef DEBUG_INPUT
2183 xmlGenericError(xmlGenericErrorContext,
2184 "I/O: read %d chars, buffer %d/%d\n",
2185 nbchars, in->buffer->use, in->buffer->size);
2186#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002187 return(nbchars);
2188}
2189
2190/**
2191 * xmlParserInputBufferRead:
2192 * @in: a buffered parser input
2193 * @len: indicative value of the amount of chars to read
2194 *
2195 * Refresh the content of the input buffer, the old data are considered
2196 * consumed
2197 * This routine handle the I18N transcoding to internal UTF-8
2198 *
2199 * Returns the number of chars read and stored in the buffer, or -1
2200 * in case of error.
2201 */
2202int
2203xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2204 /* xmlBufferEmpty(in->buffer); */
2205 if (in->readcallback != NULL)
2206 return(xmlParserInputBufferGrow(in, len));
2207 else
2208 return(-1);
2209}
2210
2211/**
2212 * xmlOutputBufferWrite:
2213 * @out: a buffered parser output
2214 * @len: the size in bytes of the array.
2215 * @buf: an char array
2216 *
2217 * Write the content of the array in the output I/O buffer
2218 * This routine handle the I18N transcoding from internal UTF-8
2219 * The buffer is lossless, i.e. will store in case of partial
2220 * or delayed writes.
2221 *
2222 * Returns the number of chars immediately written, or -1
2223 * in case of error.
2224 */
2225int
2226xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2227 int nbchars = 0; /* number of chars to output to I/O */
2228 int ret; /* return from function call */
2229 int written = 0; /* number of char written to I/O so far */
2230 int chunk; /* number of byte curreent processed from buf */
2231
2232 if (len < 0) return(0);
2233
2234 do {
2235 chunk = len;
2236 if (chunk > 4 * MINLEN)
2237 chunk = 4 * MINLEN;
2238
2239 /*
2240 * first handle encoding stuff.
2241 */
2242 if (out->encoder != NULL) {
2243 /*
2244 * Store the data in the incoming raw buffer
2245 */
2246 if (out->conv == NULL) {
2247 out->conv = xmlBufferCreate();
2248 }
2249 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2250
2251 if ((out->buffer->use < MINLEN) && (chunk == len))
2252 goto done;
2253
2254 /*
2255 * convert as much as possible to the parser reading buffer.
2256 */
2257 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2258 if (ret < 0) {
2259 xmlGenericError(xmlGenericErrorContext,
2260 "xmlOutputBufferWrite: encoder error\n");
2261 return(-1);
2262 }
2263 nbchars = out->conv->use;
2264 } else {
2265 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2266 nbchars = out->buffer->use;
2267 }
2268 buf += chunk;
2269 len -= chunk;
2270
2271 if ((nbchars < MINLEN) && (len <= 0))
2272 goto done;
2273
2274 if (out->writecallback) {
2275 /*
2276 * second write the stuff to the I/O channel
2277 */
2278 if (out->encoder != NULL) {
2279 ret = out->writecallback(out->context,
2280 (const char *)out->conv->content, nbchars);
2281 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002282 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002283 } else {
2284 ret = out->writecallback(out->context,
2285 (const char *)out->buffer->content, nbchars);
2286 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002287 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002288 }
2289 if (ret < 0) {
2290 xmlGenericError(xmlGenericErrorContext,
2291 "I/O: error %d writing %d bytes\n", ret, nbchars);
2292 return(ret);
2293 }
2294 out->written += ret;
2295 }
2296 written += nbchars;
2297 } while (len > 0);
2298
2299done:
2300#ifdef DEBUG_INPUT
2301 xmlGenericError(xmlGenericErrorContext,
2302 "I/O: wrote %d chars\n", written);
2303#endif
2304 return(written);
2305}
2306
2307/**
2308 * xmlOutputBufferWriteString:
2309 * @out: a buffered parser output
2310 * @str: a zero terminated C string
2311 *
2312 * Write the content of the string in the output I/O buffer
2313 * This routine handle the I18N transcoding from internal UTF-8
2314 * The buffer is lossless, i.e. will store in case of partial
2315 * or delayed writes.
2316 *
2317 * Returns the number of chars immediately written, or -1
2318 * in case of error.
2319 */
2320int
2321xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2322 int len;
2323
2324 if (str == NULL)
2325 return(-1);
2326 len = strlen(str);
2327
2328 if (len > 0)
2329 return(xmlOutputBufferWrite(out, len, str));
2330 return(len);
2331}
2332
2333/**
2334 * xmlOutputBufferFlush:
2335 * @out: a buffered output
2336 *
2337 * flushes the output I/O channel
2338 *
2339 * Returns the number of byte written or -1 in case of error.
2340 */
2341int
2342xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2343 int nbchars = 0, ret = 0;
2344
2345 /*
2346 * first handle encoding stuff.
2347 */
2348 if ((out->conv != NULL) && (out->encoder != NULL)) {
2349 /*
2350 * convert as much as possible to the parser reading buffer.
2351 */
2352 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2353 if (nbchars < 0) {
2354 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002355 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002356 return(-1);
2357 }
2358 }
2359
2360 /*
2361 * second flush the stuff to the I/O channel
2362 */
2363 if ((out->conv != NULL) && (out->encoder != NULL) &&
2364 (out->writecallback != NULL)) {
2365 ret = out->writecallback(out->context,
2366 (const char *)out->conv->content, out->conv->use);
2367 if (ret >= 0)
2368 xmlBufferShrink(out->conv, ret);
2369 } else if (out->writecallback != NULL) {
2370 ret = out->writecallback(out->context,
2371 (const char *)out->buffer->content, out->buffer->use);
2372 if (ret >= 0)
2373 xmlBufferShrink(out->buffer, ret);
2374 }
2375 if (ret < 0) {
2376 xmlGenericError(xmlGenericErrorContext,
2377 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2378 return(ret);
2379 }
2380 out->written += ret;
2381
2382#ifdef DEBUG_INPUT
2383 xmlGenericError(xmlGenericErrorContext,
2384 "I/O: flushed %d chars\n", ret);
2385#endif
2386 return(ret);
2387}
2388
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002389/**
Owen Taylor3473f882001-02-23 17:55:21 +00002390 * xmlParserGetDirectory:
2391 * @filename: the path to a file
2392 *
2393 * lookup the directory for that file
2394 *
2395 * Returns a new allocated string containing the directory, or NULL.
2396 */
2397char *
2398xmlParserGetDirectory(const char *filename) {
2399 char *ret = NULL;
2400 char dir[1024];
2401 char *cur;
2402 char sep = '/';
2403
2404 if (xmlInputCallbackInitialized == 0)
2405 xmlRegisterDefaultInputCallbacks();
2406
2407 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002408#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002409 sep = '\\';
2410#endif
2411
2412 strncpy(dir, filename, 1023);
2413 dir[1023] = 0;
2414 cur = &dir[strlen(dir)];
2415 while (cur > dir) {
2416 if (*cur == sep) break;
2417 cur --;
2418 }
2419 if (*cur == sep) {
2420 if (cur == dir) dir[1] = 0;
2421 else *cur = 0;
2422 ret = xmlMemStrdup(dir);
2423 } else {
2424 if (getcwd(dir, 1024) != NULL) {
2425 dir[1023] = 0;
2426 ret = xmlMemStrdup(dir);
2427 }
2428 }
2429 return(ret);
2430}
2431
2432/****************************************************************
2433 * *
2434 * External entities loading *
2435 * *
2436 ****************************************************************/
2437
Daniel Veillard561b7f82002-03-20 21:55:57 +00002438#ifdef LIBXML_CATALOG_ENABLED
2439static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002440#ifdef HAVE_STAT
2441 int ret;
2442 struct stat info;
2443 const char *path;
2444
2445 if (URL == NULL)
2446 return(0);
2447
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002448 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
Daniel Veillard6990bf32001-08-23 21:17:48 +00002449 path = &URL[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002450 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002451#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002452 path = &URL[8];
2453#else
2454 path = &URL[7];
2455#endif
2456 } else
2457 path = URL;
2458 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002459 if (ret == 0)
2460 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002461#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002462 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002463}
Daniel Veillard561b7f82002-03-20 21:55:57 +00002464#endif
Daniel Veillard6990bf32001-08-23 21:17:48 +00002465
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002466/**
Owen Taylor3473f882001-02-23 17:55:21 +00002467 * xmlDefaultExternalEntityLoader:
2468 * @URL: the URL for the entity to load
2469 * @ID: the System ID for the entity to load
2470 * @ctxt: the context in which the entity is called or NULL
2471 *
2472 * By default we don't load external entitites, yet.
2473 *
2474 * Returns a new allocated xmlParserInputPtr, or NULL.
2475 */
2476static
2477xmlParserInputPtr
2478xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2479 xmlParserCtxtPtr ctxt) {
2480 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002481 xmlChar *resource = NULL;
2482#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002483 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002484#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002485
2486#ifdef DEBUG_EXTERNAL_ENTITIES
2487 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002488 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002489#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002490#ifdef LIBXML_CATALOG_ENABLED
2491 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002492 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002493 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002494 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002495 pref = xmlCatalogGetDefaults();
2496
Daniel Veillard561b7f82002-03-20 21:55:57 +00002497 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002498 /*
2499 * Do a local lookup
2500 */
2501 if ((ctxt->catalogs != NULL) &&
2502 ((pref == XML_CATA_ALLOW_ALL) ||
2503 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2504 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2505 (const xmlChar *)ID,
2506 (const xmlChar *)URL);
2507 }
2508 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002509 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002510 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002511 if ((resource == NULL) &&
2512 ((pref == XML_CATA_ALLOW_ALL) ||
2513 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002514 resource = xmlCatalogResolve((const xmlChar *)ID,
2515 (const xmlChar *)URL);
2516 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002517 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002518 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002519
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002520 /*
2521 * TODO: do an URI lookup on the reference
2522 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002523 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002524 xmlChar *tmp = NULL;
2525
2526 if ((ctxt->catalogs != NULL) &&
2527 ((pref == XML_CATA_ALLOW_ALL) ||
2528 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2529 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2530 }
2531 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002532 ((pref == XML_CATA_ALLOW_ALL) ||
2533 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002534 tmp = xmlCatalogResolveURI(resource);
2535 }
2536
2537 if (tmp != NULL) {
2538 xmlFree(resource);
2539 resource = tmp;
2540 }
2541 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002542 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002543#endif
2544
2545 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002546 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002547
2548 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002549 if (ID == NULL)
2550 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002551 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2552 (ctxt->sax->error != NULL))
2553 ctxt->sax->error(ctxt,
2554 "failed to load external entity \"%s\"\n", ID);
2555 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002556 ctxt->sax->warning(ctxt,
2557 "failed to load external entity \"%s\"\n", ID);
2558 return(NULL);
2559 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002560 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002561 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002562 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2563 (ctxt->sax->error != NULL))
2564 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002565 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002566 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002567 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002568 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002569 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002570 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002571 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002572 return(ret);
2573}
2574
2575static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2576 xmlDefaultExternalEntityLoader;
2577
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002578/**
Owen Taylor3473f882001-02-23 17:55:21 +00002579 * xmlSetExternalEntityLoader:
2580 * @f: the new entity resolver function
2581 *
2582 * Changes the defaultexternal entity resolver function for the application
2583 */
2584void
2585xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2586 xmlCurrentExternalEntityLoader = f;
2587}
2588
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002589/**
Owen Taylor3473f882001-02-23 17:55:21 +00002590 * xmlGetExternalEntityLoader:
2591 *
2592 * Get the default external entity resolver function for the application
2593 *
2594 * Returns the xmlExternalEntityLoader function pointer
2595 */
2596xmlExternalEntityLoader
2597xmlGetExternalEntityLoader(void) {
2598 return(xmlCurrentExternalEntityLoader);
2599}
2600
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002601/**
Owen Taylor3473f882001-02-23 17:55:21 +00002602 * xmlLoadExternalEntity:
2603 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002604 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002605 * @ctxt: the context in which the entity is called or NULL
2606 *
2607 * Load an external entity, note that the use of this function for
2608 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002609 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002610 *
2611 * Returns the xmlParserInputPtr or NULL
2612 */
2613xmlParserInputPtr
2614xmlLoadExternalEntity(const char *URL, const char *ID,
2615 xmlParserCtxtPtr ctxt) {
2616 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2617}
2618
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002619/************************************************************************
2620 * *
2621 * Disabling Network access *
2622 * *
2623 ************************************************************************/
2624
2625#ifdef LIBXML_CATALOG_ENABLED
2626static int
2627xmlNoNetExists(const char *URL)
2628{
2629#ifdef HAVE_STAT
2630 int ret;
2631 struct stat info;
2632 const char *path;
2633
2634 if (URL == NULL)
2635 return (0);
2636
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002637 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002638 path = &URL[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002639 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002640#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002641 path = &URL[8];
2642#else
2643 path = &URL[7];
2644#endif
2645 } else
2646 path = URL;
2647 ret = stat(path, &info);
2648 if (ret == 0)
2649 return (1);
2650#endif
2651 return (0);
2652}
2653#endif
2654
2655/**
2656 * xmlNoNetExternalEntityLoader:
2657 * @URL: the URL for the entity to load
2658 * @ID: the System ID for the entity to load
2659 * @ctxt: the context in which the entity is called or NULL
2660 *
2661 * A specific entity loader disabling network accesses, though still
2662 * allowing local catalog accesses for resolution.
2663 *
2664 * Returns a new allocated xmlParserInputPtr, or NULL.
2665 */
2666xmlParserInputPtr
2667xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2668 xmlParserCtxtPtr ctxt) {
2669 xmlParserInputPtr input = NULL;
2670 xmlChar *resource = NULL;
2671
2672#ifdef LIBXML_CATALOG_ENABLED
2673 xmlCatalogAllow pref;
2674
2675 /*
2676 * If the resource doesn't exists as a file,
2677 * try to load it from the resource pointed in the catalogs
2678 */
2679 pref = xmlCatalogGetDefaults();
2680
2681 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2682 /*
2683 * Do a local lookup
2684 */
2685 if ((ctxt->catalogs != NULL) &&
2686 ((pref == XML_CATA_ALLOW_ALL) ||
2687 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2688 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2689 (const xmlChar *)ID,
2690 (const xmlChar *)URL);
2691 }
2692 /*
2693 * Try a global lookup
2694 */
2695 if ((resource == NULL) &&
2696 ((pref == XML_CATA_ALLOW_ALL) ||
2697 (pref == XML_CATA_ALLOW_GLOBAL))) {
2698 resource = xmlCatalogResolve((const xmlChar *)ID,
2699 (const xmlChar *)URL);
2700 }
2701 if ((resource == NULL) && (URL != NULL))
2702 resource = xmlStrdup((const xmlChar *) URL);
2703
2704 /*
2705 * TODO: do an URI lookup on the reference
2706 */
2707 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2708 xmlChar *tmp = NULL;
2709
2710 if ((ctxt->catalogs != NULL) &&
2711 ((pref == XML_CATA_ALLOW_ALL) ||
2712 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2713 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2714 }
2715 if ((tmp == NULL) &&
2716 ((pref == XML_CATA_ALLOW_ALL) ||
2717 (pref == XML_CATA_ALLOW_GLOBAL))) {
2718 tmp = xmlCatalogResolveURI(resource);
2719 }
2720
2721 if (tmp != NULL) {
2722 xmlFree(resource);
2723 resource = tmp;
2724 }
2725 }
2726 }
2727#endif
2728 if (resource == NULL)
2729 resource = (xmlChar *) URL;
2730
2731 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002732 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2733 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002734 xmlGenericError(xmlGenericErrorContext,
2735 "Attempt to load network entity %s \n", resource);
2736
2737 if (resource != (xmlChar *) URL)
2738 xmlFree(resource);
2739 return(NULL);
2740 }
2741 }
2742 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2743 if (resource != (xmlChar *) URL)
2744 xmlFree(resource);
2745 return(input);
2746}
2747