blob: 2811058cdc2edf2d077c19a933ecb97be6611097 [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
Daniel Veillarde50f3b52002-03-20 19:24:21 +000036#ifdef HAVE_SYS_MMAN_H
37#include <sys/mman.h>
38/* seems needed for Solaris */
39#ifndef MAP_FAILED
40#define MAP_FAILED ((void *) -1)
41#endif
42#endif
43
Owen Taylor3473f882001-02-23 17:55:21 +000044/* Figure a portable way to know if a file is a directory. */
45#ifndef HAVE_STAT
46# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000047 /* MS C library seems to define stat and _stat. The definition
48 is identical. Still, mapping them to each other causes a warning. */
49# ifndef _MSC_VER
50# define stat(x,y) _stat(x,y)
51# endif
Owen Taylor3473f882001-02-23 17:55:21 +000052# define HAVE_STAT
53# endif
54#endif
55#ifdef HAVE_STAT
56# ifndef S_ISDIR
57# ifdef _S_ISDIR
58# define S_ISDIR(x) _S_ISDIR(x)
59# else
60# ifdef S_IFDIR
61# ifndef S_IFMT
62# ifdef _S_IFMT
63# define S_IFMT _S_IFMT
64# endif
65# endif
66# ifdef S_IFMT
67# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
68# endif
69# endif
70# endif
71# endif
72#endif
73
74#include <libxml/xmlmemory.h>
75#include <libxml/parser.h>
76#include <libxml/parserInternals.h>
77#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000078#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000079#include <libxml/nanohttp.h>
80#include <libxml/nanoftp.h>
81#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000082#ifdef LIBXML_CATALOG_ENABLED
83#include <libxml/catalog.h>
84#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000085#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000086
87#ifdef VMS
88#define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
89#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
90#endif
91
Daniel Veillardf012a642001-07-23 19:10:52 +000092/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000093/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000094/* #define DEBUG_INPUT */
95
96#ifdef DEBUG_INPUT
97#define MINLEN 40
98#else
99#define MINLEN 4000
100#endif
101
102/*
103 * Input I/O callback sets
104 */
105typedef struct _xmlInputCallback {
106 xmlInputMatchCallback matchcallback;
107 xmlInputOpenCallback opencallback;
108 xmlInputReadCallback readcallback;
109 xmlInputCloseCallback closecallback;
110} xmlInputCallback;
111
112#define MAX_INPUT_CALLBACK 15
113
Daniel Veillard22090732001-07-16 00:06:07 +0000114static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
115static int xmlInputCallbackNr = 0;
116static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000117
118/*
119 * Output I/O callback sets
120 */
121typedef struct _xmlOutputCallback {
122 xmlOutputMatchCallback matchcallback;
123 xmlOutputOpenCallback opencallback;
124 xmlOutputWriteCallback writecallback;
125 xmlOutputCloseCallback closecallback;
126} xmlOutputCallback;
127
128#define MAX_OUTPUT_CALLBACK 15
129
Daniel Veillard22090732001-07-16 00:06:07 +0000130static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
131static int xmlOutputCallbackNr = 0;
132static int xmlOutputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000133
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000134/**
135 * xmlCleanupInputCallbacks:
136 *
137 * clears the entire input callback table. this includes the
138 * compiled-in I/O.
139 */
140void
141xmlCleanupInputCallbacks(void)
142{
143 int i;
144
145 if (!xmlInputCallbackInitialized)
146 return;
147
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000148 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000149 xmlInputCallbackTable[i].matchcallback = NULL;
150 xmlInputCallbackTable[i].opencallback = NULL;
151 xmlInputCallbackTable[i].readcallback = NULL;
152 xmlInputCallbackTable[i].closecallback = NULL;
153 }
154
155 xmlInputCallbackNr = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000156}
157
158/**
159 * xmlCleanupOutputCallbacks:
160 *
161 * clears the entire output callback table. this includes the
162 * compiled-in I/O callbacks.
163 */
164void
165xmlCleanupOutputCallbacks(void)
166{
167 int i;
168
169 if (!xmlOutputCallbackInitialized)
170 return;
171
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000172 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000173 xmlOutputCallbackTable[i].matchcallback = NULL;
174 xmlOutputCallbackTable[i].opencallback = NULL;
175 xmlOutputCallbackTable[i].writecallback = NULL;
176 xmlOutputCallbackTable[i].closecallback = NULL;
177 }
178
179 xmlOutputCallbackNr = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000180}
181
Owen Taylor3473f882001-02-23 17:55:21 +0000182/************************************************************************
183 * *
184 * Standard I/O for file accesses *
185 * *
186 ************************************************************************/
187
188/**
189 * xmlCheckFilename
190 * @path: the path to check
191 *
192 * function checks to see if @path is a valid source
193 * (file, socket...) for XML.
194 *
195 * if stat is not available on the target machine,
196 * returns 1. if stat fails, returns 0 (if calling
197 * stat on the filename fails, it can't be right).
198 * if stat succeeds and the file is a directory,
199 * sets errno to EISDIR and returns 0. otherwise
200 * returns 1.
201 */
202
203static int
204xmlCheckFilename (const char *path)
205{
206#ifdef HAVE_STAT
207#ifdef S_ISDIR
208 struct stat stat_buffer;
209
210 if (stat(path, &stat_buffer) == -1)
211 return 0;
212
213 if (S_ISDIR(stat_buffer.st_mode)) {
214 errno = EISDIR;
215 return 0;
216 }
217
218#endif
219#endif
220 return 1;
221}
222
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000223static int
Owen Taylor3473f882001-02-23 17:55:21 +0000224xmlNop(void) {
225 return(0);
226}
227
228/**
Owen Taylor3473f882001-02-23 17:55:21 +0000229 * xmlFdRead:
230 * @context: the I/O context
231 * @buffer: where to drop data
232 * @len: number of bytes to read
233 *
234 * Read @len bytes to @buffer from the I/O channel.
235 *
236 * Returns the number of bytes written
237 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000238static int
Owen Taylor3473f882001-02-23 17:55:21 +0000239xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000240 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000241}
242
243/**
244 * xmlFdWrite:
245 * @context: the I/O context
246 * @buffer: where to get data
247 * @len: number of bytes to write
248 *
249 * Write @len bytes from @buffer to the I/O channel.
250 *
251 * Returns the number of bytes written
252 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000253static int
Owen Taylor3473f882001-02-23 17:55:21 +0000254xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000255 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000256}
257
258/**
259 * xmlFdClose:
260 * @context: the I/O context
261 *
262 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000263 *
264 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000265 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000266static int
Owen Taylor3473f882001-02-23 17:55:21 +0000267xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000268 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000269}
270
271/**
272 * xmlFileMatch:
273 * @filename: the URI for matching
274 *
275 * input from FILE *
276 *
277 * Returns 1 if matches, 0 otherwise
278 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000279static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000280xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000281 return(1);
282}
283
284/**
285 * xmlFileOpen:
286 * @filename: the URI for matching
287 *
288 * input from FILE *, supports compressed input
289 * if @filename is " " then the standard input is used
290 *
291 * Returns an I/O context or NULL in case of error
292 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000293static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000294xmlFileOpen (const char *filename) {
295 const char *path = NULL;
296 FILE *fd;
297
298 if (!strcmp(filename, "-")) {
299 fd = stdin;
300 return((void *) fd);
301 }
302
303 if (!strncmp(filename, "file://localhost", 16))
304 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000305 else if (!strncmp(filename, "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000306#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000307 path = &filename[8];
308#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000309 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000310#endif
311 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000312 path = filename;
313
314 if (path == NULL)
315 return(NULL);
316 if (!xmlCheckFilename(path))
317 return(NULL);
318
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000319#if defined(WIN32) || defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000320 fd = fopen(path, "rb");
321#else
322 fd = fopen(path, "r");
323#endif /* WIN32 */
324 return((void *) fd);
325}
326
327/**
328 * xmlFileOpenW:
329 * @filename: the URI for matching
330 *
331 * output to from FILE *,
332 * if @filename is "-" then the standard output is used
333 *
334 * Returns an I/O context or NULL in case of error
335 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000336static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000337xmlFileOpenW (const char *filename) {
338 const char *path = NULL;
339 FILE *fd;
340
341 if (!strcmp(filename, "-")) {
342 fd = stdout;
343 return((void *) fd);
344 }
345
346 if (!strncmp(filename, "file://localhost", 16))
347 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000348 else if (!strncmp(filename, "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000349#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000350 path = &filename[8];
351#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000352 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000353#endif
354 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000355 path = filename;
356
357 if (path == NULL)
358 return(NULL);
359
360 fd = fopen(path, "w");
361 return((void *) fd);
362}
363
364/**
365 * xmlFileRead:
366 * @context: the I/O context
367 * @buffer: where to drop data
368 * @len: number of bytes to write
369 *
370 * Read @len bytes to @buffer from the I/O channel.
371 *
372 * Returns the number of bytes written
373 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000374static int
Owen Taylor3473f882001-02-23 17:55:21 +0000375xmlFileRead (void * context, char * buffer, int len) {
376 return(fread(&buffer[0], 1, len, (FILE *) context));
377}
378
379/**
380 * xmlFileWrite:
381 * @context: the I/O context
382 * @buffer: where to drop data
383 * @len: number of bytes to write
384 *
385 * Write @len bytes from @buffer to the I/O channel.
386 *
387 * Returns the number of bytes written
388 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000389static int
Owen Taylor3473f882001-02-23 17:55:21 +0000390xmlFileWrite (void * context, const char * buffer, int len) {
391 return(fwrite(&buffer[0], 1, len, (FILE *) context));
392}
393
394/**
395 * xmlFileClose:
396 * @context: the I/O context
397 *
398 * Close an I/O channel
399 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000400static int
Owen Taylor3473f882001-02-23 17:55:21 +0000401xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000402 FILE *fil;
403
404 fil = (FILE *) context;
405 if (fil == stdin)
406 return(0);
407 if (fil == stdout)
408 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000409 if (fil == stderr)
410 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000411 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000412}
413
414/**
415 * xmlFileFlush:
416 * @context: the I/O context
417 *
418 * Flush an I/O channel
419 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000420static int
Owen Taylor3473f882001-02-23 17:55:21 +0000421xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000422 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000423}
424
425#ifdef HAVE_ZLIB_H
426/************************************************************************
427 * *
428 * I/O for compressed file accesses *
429 * *
430 ************************************************************************/
431/**
432 * xmlGzfileMatch:
433 * @filename: the URI for matching
434 *
435 * input from compressed file test
436 *
437 * Returns 1 if matches, 0 otherwise
438 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000439static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000440xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000441 return(1);
442}
443
444/**
445 * xmlGzfileOpen:
446 * @filename: the URI for matching
447 *
448 * input from compressed file open
449 * if @filename is " " then the standard input is used
450 *
451 * Returns an I/O context or NULL in case of error
452 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000453static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000454xmlGzfileOpen (const char *filename) {
455 const char *path = NULL;
456 gzFile fd;
457
458 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000459 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000460 return((void *) fd);
461 }
462
463 if (!strncmp(filename, "file://localhost", 16))
464 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000465 else if (!strncmp(filename, "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000466#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000467 path = &filename[8];
468#else
Owen Taylor3473f882001-02-23 17:55:21 +0000469 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000470#endif
471 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000472 path = filename;
473
474 if (path == NULL)
475 return(NULL);
476 if (!xmlCheckFilename(path))
477 return(NULL);
478
479 fd = gzopen(path, "rb");
480 return((void *) fd);
481}
482
483/**
484 * xmlGzfileOpenW:
485 * @filename: the URI for matching
486 * @compression: the compression factor (0 - 9 included)
487 *
488 * input from compressed file open
489 * if @filename is " " then the standard input is used
490 *
491 * Returns an I/O context or NULL in case of error
492 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000493static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000494xmlGzfileOpenW (const char *filename, int compression) {
495 const char *path = NULL;
496 char mode[15];
497 gzFile fd;
498
499 sprintf(mode, "wb%d", compression);
500 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000501 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000502 return((void *) fd);
503 }
504
505 if (!strncmp(filename, "file://localhost", 16))
506 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000507 else if (!strncmp(filename, "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000508#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000509 path = &filename[8];
510#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000511 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000512#endif
513 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000514 path = filename;
515
516 if (path == NULL)
517 return(NULL);
518
519 fd = gzopen(path, mode);
520 return((void *) fd);
521}
522
523/**
524 * xmlGzfileRead:
525 * @context: the I/O context
526 * @buffer: where to drop data
527 * @len: number of bytes to write
528 *
529 * Read @len bytes to @buffer from the compressed I/O channel.
530 *
531 * Returns the number of bytes written
532 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000533static int
Owen Taylor3473f882001-02-23 17:55:21 +0000534xmlGzfileRead (void * context, char * buffer, int len) {
535 return(gzread((gzFile) context, &buffer[0], len));
536}
537
538/**
539 * xmlGzfileWrite:
540 * @context: the I/O context
541 * @buffer: where to drop data
542 * @len: number of bytes to write
543 *
544 * Write @len bytes from @buffer to the compressed I/O channel.
545 *
546 * Returns the number of bytes written
547 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000548static int
Owen Taylor3473f882001-02-23 17:55:21 +0000549xmlGzfileWrite (void * context, const char * buffer, int len) {
550 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
551}
552
553/**
554 * xmlGzfileClose:
555 * @context: the I/O context
556 *
557 * Close a compressed I/O channel
558 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000559static int
Owen Taylor3473f882001-02-23 17:55:21 +0000560xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000561 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000562}
563#endif /* HAVE_ZLIB_H */
564
565#ifdef LIBXML_HTTP_ENABLED
566/************************************************************************
567 * *
568 * I/O for HTTP file accesses *
569 * *
570 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000571
572typedef struct xmlIOHTTPWriteCtxt_
573{
574 int compression;
575
576 char * uri;
577
578 void * doc_buff;
579
580} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
581
582#ifdef HAVE_ZLIB_H
583
584#define DFLT_WBITS ( -15 )
585#define DFLT_MEM_LVL ( 8 )
586#define GZ_MAGIC1 ( 0x1f )
587#define GZ_MAGIC2 ( 0x8b )
588#define LXML_ZLIB_OS_CODE ( 0x03 )
589#define INIT_HTTP_BUFF_SIZE ( 32768 )
590#define DFLT_ZLIB_RATIO ( 5 )
591
592/*
593** Data structure and functions to work with sending compressed data
594** via HTTP.
595*/
596
597typedef struct xmlZMemBuff_
598{
599 unsigned long size;
600 unsigned long crc;
601
602 unsigned char * zbuff;
603 z_stream zctrl;
604
605} xmlZMemBuff, *xmlZMemBuffPtr;
606
607/**
608 * append_reverse_ulong
609 * @buff: Compressed memory buffer
610 * @data: Unsigned long to append
611 *
612 * Append a unsigned long in reverse byte order to the end of the
613 * memory buffer.
614 */
615static void
616append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
617
618 int idx;
619
620 if ( buff == NULL )
621 return;
622
623 /*
624 ** This is plagiarized from putLong in gzio.c (zlib source) where
625 ** the number "4" is hardcoded. If zlib is ever patched to
626 ** support 64 bit file sizes, this code would need to be patched
627 ** as well.
628 */
629
630 for ( idx = 0; idx < 4; idx++ ) {
631 *buff->zctrl.next_out = ( data & 0xff );
632 data >>= 8;
633 buff->zctrl.next_out++;
634 }
635
636 return;
637}
638
639/**
640 *
641 * xmlFreeZMemBuff
642 * @buff: The memory buffer context to clear
643 *
644 * Release all the resources associated with the compressed memory buffer.
645 */
646static void
647xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
648
649 int z_err;
650
651 if ( buff == NULL )
652 return;
653
654 xmlFree( buff->zbuff );
655 z_err = deflateEnd( &buff->zctrl );
656#ifdef DEBUG_HTTP
657 if ( z_err != Z_OK )
658 xmlGenericError( xmlGenericErrorContext,
659 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
660 z_err );
661#endif
662
663 xmlFree( buff );
664 return;
665}
666
667/**
668 * xmlCreateZMemBuff
669 *@compression: Compression value to use
670 *
671 * Create a memory buffer to hold the compressed XML document. The
672 * compressed document in memory will end up being identical to what
673 * would be created if gzopen/gzwrite/gzclose were being used to
674 * write the document to disk. The code for the header/trailer data to
675 * the compression is plagiarized from the zlib source files.
676 */
677static void *
678xmlCreateZMemBuff( int compression ) {
679
680 int z_err;
681 int hdr_lgth;
682 xmlZMemBuffPtr buff = NULL;
683
684 if ( ( compression < 1 ) || ( compression > 9 ) )
685 return ( NULL );
686
687 /* Create the control and data areas */
688
689 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
690 if ( buff == NULL ) {
691 xmlGenericError( xmlGenericErrorContext,
692 "xmlCreateZMemBuff: %s\n",
693 "Failure allocating buffer context." );
694 return ( NULL );
695 }
696
697 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
698 buff->size = INIT_HTTP_BUFF_SIZE;
699 buff->zbuff = xmlMalloc( buff->size );
700 if ( buff->zbuff == NULL ) {
701 xmlFreeZMemBuff( buff );
702 xmlGenericError( xmlGenericErrorContext,
703 "xmlCreateZMemBuff: %s\n",
704 "Failure allocating data buffer." );
705 return ( NULL );
706 }
707
708 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
709 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
710 if ( z_err != Z_OK ) {
711 xmlFreeZMemBuff( buff );
712 buff = NULL;
713 xmlGenericError( xmlGenericErrorContext,
714 "xmlCreateZMemBuff: %s %d\n",
715 "Error initializing compression context. ZLIB error:",
716 z_err );
717 return ( NULL );
718 }
719
720 /* Set the header data. The CRC will be needed for the trailer */
721
722 buff->crc = crc32( 0L, Z_NULL, 0 );
723 hdr_lgth = sprintf( (char *)buff->zbuff, "%c%c%c%c%c%c%c%c%c%c",
724 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
725 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
726 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
727 buff->zctrl.avail_out = buff->size - hdr_lgth;
728
729 return ( buff );
730}
731
732/**
733 * xmlZMemBuffExtend
734 * @buff: Buffer used to compress and consolidate data.
735 * @ext_amt: Number of bytes to extend the buffer.
736 *
737 * Extend the internal buffer used to store the compressed data by the
738 * specified amount.
739 *
740 * Returns 0 on success or -1 on failure to extend the buffer. On failure
741 * the original buffer still exists at the original size.
742 */
743static int
744xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
745
746 int rc = -1;
747 size_t new_size;
748 size_t cur_used;
749
750 unsigned char * tmp_ptr = NULL;
751
752 if ( buff == NULL )
753 return ( -1 );
754
755 else if ( ext_amt == 0 )
756 return ( 0 );
757
758 cur_used = buff->zctrl.next_out - buff->zbuff;
759 new_size = buff->size + ext_amt;
760
761#ifdef DEBUG_HTTP
762 if ( cur_used > new_size )
763 xmlGenericError( xmlGenericErrorContext,
764 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
765 "Buffer overwrite detected during compressed memory",
766 "buffer extension. Overflowed by",
767 (cur_used - new_size ) );
768#endif
769
770 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
771 if ( tmp_ptr != NULL ) {
772 rc = 0;
773 buff->size = new_size;
774 buff->zbuff = tmp_ptr;
775 buff->zctrl.next_out = tmp_ptr + cur_used;
776 buff->zctrl.avail_out = new_size - cur_used;
777 }
778 else {
779 xmlGenericError( xmlGenericErrorContext,
780 "xmlZMemBuffExtend: %s %lu bytes.\n",
781 "Allocation failure extending output buffer to",
782 new_size );
783 }
784
785 return ( rc );
786}
787
788/**
789 * xmlZMemBuffAppend
790 * @buff: Buffer used to compress and consolidate data
791 * @src: Uncompressed source content to append to buffer
792 * @len: Length of source data to append to buffer
793 *
794 * Compress and append data to the internal buffer. The data buffer
795 * will be expanded if needed to store the additional data.
796 *
797 * Returns the number of bytes appended to the buffer or -1 on error.
798 */
799static int
800xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
801
802 int z_err;
803 size_t min_accept;
804
805 if ( ( buff == NULL ) || ( src == NULL ) )
806 return ( -1 );
807
808 buff->zctrl.avail_in = len;
809 buff->zctrl.next_in = (unsigned char *)src;
810 while ( buff->zctrl.avail_in > 0 ) {
811 /*
812 ** Extend the buffer prior to deflate call if a reasonable amount
813 ** of output buffer space is not available.
814 */
815 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
816 if ( buff->zctrl.avail_out <= min_accept ) {
817 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
818 return ( -1 );
819 }
820
821 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
822 if ( z_err != Z_OK ) {
823 xmlGenericError( xmlGenericErrorContext,
824 "xmlZMemBuffAppend: %s %d %s - %d",
825 "Compression error while appending",
826 len, "bytes to buffer. ZLIB error", z_err );
827 return ( -1 );
828 }
829 }
830
831 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
832
833 return ( len );
834}
835
836/**
837 * xmlZMemBuffGetContent
838 * @buff: Compressed memory content buffer
839 * @data_ref: Pointer reference to point to compressed content
840 *
841 * Flushes the compression buffers, appends gzip file trailers and
842 * returns the compressed content and length of the compressed data.
843 * NOTE: The gzip trailer code here is plagiarized from zlib source.
844 *
845 * Returns the length of the compressed data or -1 on error.
846 */
847static int
848xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
849
850 int zlgth = -1;
851 int z_err;
852
853 if ( ( buff == NULL ) || ( data_ref == NULL ) )
854 return ( -1 );
855
856 /* Need to loop until compression output buffers are flushed */
857
858 do
859 {
860 z_err = deflate( &buff->zctrl, Z_FINISH );
861 if ( z_err == Z_OK ) {
862 /* In this case Z_OK means more buffer space needed */
863
864 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
865 return ( -1 );
866 }
867 }
868 while ( z_err == Z_OK );
869
870 /* If the compression state is not Z_STREAM_END, some error occurred */
871
872 if ( z_err == Z_STREAM_END ) {
873
874 /* Need to append the gzip data trailer */
875
876 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
877 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
878 return ( -1 );
879 }
880
881 /*
882 ** For whatever reason, the CRC and length data are pushed out
883 ** in reverse byte order. So a memcpy can't be used here.
884 */
885
886 append_reverse_ulong( buff, buff->crc );
887 append_reverse_ulong( buff, buff->zctrl.total_in );
888
889 zlgth = buff->zctrl.next_out - buff->zbuff;
890 *data_ref = (char *)buff->zbuff;
891 }
892
893 else
894 xmlGenericError( xmlGenericErrorContext,
895 "xmlZMemBuffGetContent: %s - %d\n",
896 "Error flushing zlib buffers. Error code", z_err );
897
898 return ( zlgth );
899}
900#endif /* HAVE_ZLIB_H */
901
902/**
903 * xmlFreeHTTPWriteCtxt
904 * @ctxt: Context to cleanup
905 *
906 * Free allocated memory and reclaim system resources.
907 *
908 * No return value.
909 */
910static void
911xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
912{
913 if ( ctxt->uri != NULL )
914 free( ctxt->uri );
915
916 if ( ctxt->doc_buff != NULL ) {
917
918#ifdef HAVE_ZLIB_H
919 if ( ctxt->compression > 0 ) {
920 xmlFreeZMemBuff( ctxt->doc_buff );
921 }
922 else
923#endif
924 {
925 xmlOutputBufferClose( ctxt->doc_buff );
926 }
927 }
928
929 free( ctxt );
930 return;
931}
932
933
Owen Taylor3473f882001-02-23 17:55:21 +0000934/**
935 * xmlIOHTTPMatch:
936 * @filename: the URI for matching
937 *
938 * check if the URI matches an HTTP one
939 *
940 * Returns 1 if matches, 0 otherwise
941 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000942static int
Owen Taylor3473f882001-02-23 17:55:21 +0000943xmlIOHTTPMatch (const char *filename) {
944 if (!strncmp(filename, "http://", 7))
945 return(1);
946 return(0);
947}
948
949/**
950 * xmlIOHTTPOpen:
951 * @filename: the URI for matching
952 *
953 * open an HTTP I/O channel
954 *
955 * Returns an I/O context or NULL in case of error
956 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000957static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000958xmlIOHTTPOpen (const char *filename) {
959 return(xmlNanoHTTPOpen(filename, NULL));
960}
961
962/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000963 * xmlIOHTTPOpenW
964 * @post_uri: The destination URI for the document
965 * @compression: The compression desired for the document.
966 *
967 * Open a temporary buffer to collect the document for a subsequent HTTP POST
968 * request. Non-static as is called from the output buffer creation routine.
969 *
970 * Returns an I/O context or NULL in case of error.
971 */
972
973void *
Daniel Veillard572577e2002-01-18 16:23:55 +0000974xmlIOHTTPOpenW(const char *post_uri, int compression)
975{
Daniel Veillardf012a642001-07-23 19:10:52 +0000976
Daniel Veillard572577e2002-01-18 16:23:55 +0000977 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +0000978
Daniel Veillard572577e2002-01-18 16:23:55 +0000979 if (post_uri == NULL)
980 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000981
Daniel Veillard572577e2002-01-18 16:23:55 +0000982 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
983 if (ctxt == NULL) {
984 xmlGenericError(xmlGenericErrorContext,
985 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
986 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000987 }
988
Daniel Veillard572577e2002-01-18 16:23:55 +0000989 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +0000990
Daniel Veillard572577e2002-01-18 16:23:55 +0000991 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
992 if (ctxt->uri == NULL) {
993 xmlGenericError(xmlGenericErrorContext,
994 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
995 xmlFreeHTTPWriteCtxt(ctxt);
996 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000997 }
998
999 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001000 * ** Since the document length is required for an HTTP post,
1001 * ** need to put the document into a buffer. A memory buffer
1002 * ** is being used to avoid pushing the data to disk and back.
1003 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001004
1005#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001006 if ((compression > 0) && (compression <= 9)) {
1007
1008 ctxt->compression = compression;
1009 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1010 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001011#endif
1012 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001013 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001014
Daniel Veillard572577e2002-01-18 16:23:55 +00001015 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001016 }
1017
Daniel Veillard572577e2002-01-18 16:23:55 +00001018 if (ctxt->doc_buff == NULL) {
1019 xmlFreeHTTPWriteCtxt(ctxt);
1020 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001021 }
1022
Daniel Veillard572577e2002-01-18 16:23:55 +00001023 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001024}
1025
1026/**
1027 * xmlIOHTTPDfltOpenW
1028 * @post_uri: The destination URI for this document.
1029 *
1030 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1031 * HTTP post command. This function should generally not be used as
1032 * the open callback is short circuited in xmlOutputBufferCreateFile.
1033 *
1034 * Returns a pointer to the new IO context.
1035 */
1036static void *
1037xmlIOHTTPDfltOpenW( const char * post_uri ) {
1038 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1039}
1040
1041/**
Owen Taylor3473f882001-02-23 17:55:21 +00001042 * xmlIOHTTPRead:
1043 * @context: the I/O context
1044 * @buffer: where to drop data
1045 * @len: number of bytes to write
1046 *
1047 * Read @len bytes to @buffer from the I/O channel.
1048 *
1049 * Returns the number of bytes written
1050 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001051static int
Owen Taylor3473f882001-02-23 17:55:21 +00001052xmlIOHTTPRead(void * context, char * buffer, int len) {
1053 return(xmlNanoHTTPRead(context, &buffer[0], len));
1054}
1055
1056/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001057 * xmlIOHTTPWrite
1058 * @context: previously opened writing context
1059 * @buffer: data to output to temporary buffer
1060 * @len: bytes to output
1061 *
1062 * Collect data from memory buffer into a temporary file for later
1063 * processing.
1064 *
1065 * Returns number of bytes written.
1066 */
1067
1068static int
1069xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1070
1071 xmlIOHTTPWriteCtxtPtr ctxt = context;
1072
1073 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1074 return ( -1 );
1075
1076 if ( len > 0 ) {
1077
1078 /* Use gzwrite or fwrite as previously setup in the open call */
1079
1080#ifdef HAVE_ZLIB_H
1081 if ( ctxt->compression > 0 )
1082 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1083
1084 else
1085#endif
1086 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1087
1088 if ( len < 0 ) {
1089 xmlGenericError( xmlGenericErrorContext,
1090 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1091 "Error appending to internal buffer.",
1092 "Error sending document to URI",
1093 ctxt->uri );
1094 }
1095 }
1096
1097 return ( len );
1098}
1099
1100
1101/**
Owen Taylor3473f882001-02-23 17:55:21 +00001102 * xmlIOHTTPClose:
1103 * @context: the I/O context
1104 *
1105 * Close an HTTP I/O channel
1106 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001107static int
Owen Taylor3473f882001-02-23 17:55:21 +00001108xmlIOHTTPClose (void * context) {
1109 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001110 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001111}
Daniel Veillardf012a642001-07-23 19:10:52 +00001112
1113/**
1114 * xmlIOHTTCloseWrite
1115 * @context: The I/O context
1116 * @http_mthd: The HTTP method to be used when sending the data
1117 *
1118 * Close the transmit HTTP I/O channel and actually send the data.
1119 */
1120static int
1121xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1122
1123 int close_rc = -1;
1124 int http_rtn = 0;
1125 int content_lgth = 0;
1126 xmlIOHTTPWriteCtxtPtr ctxt = context;
1127
1128 char * http_content = NULL;
1129 char * content_encoding = NULL;
1130 char * content_type = (char *) "text/xml";
1131 void * http_ctxt = NULL;
1132
1133 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1134 return ( -1 );
1135
1136 /* Retrieve the content from the appropriate buffer */
1137
1138#ifdef HAVE_ZLIB_H
1139
1140 if ( ctxt->compression > 0 ) {
1141 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1142 content_encoding = (char *) "Content-Encoding: gzip";
1143 }
1144 else
1145#endif
1146 {
1147 /* Pull the data out of the memory output buffer */
1148
1149 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1150 http_content = (char *)dctxt->buffer->content;
1151 content_lgth = dctxt->buffer->use;
1152 }
1153
1154 if ( http_content == NULL ) {
1155 xmlGenericError( xmlGenericErrorContext,
1156 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1157 "Error retrieving content.\nUnable to",
1158 http_mthd, "data to URI", ctxt->uri );
1159 }
1160
1161 else {
1162
1163 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1164 &content_type, content_encoding,
1165 content_lgth );
1166
1167 if ( http_ctxt != NULL ) {
1168#ifdef DEBUG_HTTP
1169 /* If testing/debugging - dump reply with request content */
1170
1171 FILE * tst_file = NULL;
1172 char buffer[ 4096 ];
1173 char * dump_name = NULL;
1174 int avail;
1175
1176 xmlGenericError( xmlGenericErrorContext,
1177 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1178 http_mthd, ctxt->uri,
1179 xmlNanoHTTPReturnCode( http_ctxt ) );
1180
1181 /*
1182 ** Since either content or reply may be gzipped,
1183 ** dump them to separate files instead of the
1184 ** standard error context.
1185 */
1186
1187 dump_name = tempnam( NULL, "lxml" );
1188 if ( dump_name != NULL ) {
1189 (void)sprintf( buffer, "%s.content", dump_name );
1190
1191 tst_file = fopen( buffer, "w" );
1192 if ( tst_file != NULL ) {
1193 xmlGenericError( xmlGenericErrorContext,
1194 "Transmitted content saved in file: %s\n", buffer );
1195
1196 fwrite( http_content, sizeof( char ),
1197 content_lgth, tst_file );
1198 fclose( tst_file );
1199 }
1200
1201 (void)sprintf( buffer, "%s.reply", dump_name );
1202 tst_file = fopen( buffer, "w" );
1203 if ( tst_file != NULL ) {
1204 xmlGenericError( xmlGenericErrorContext,
1205 "Reply content saved in file: %s\n", buffer );
1206
1207
1208 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1209 buffer, sizeof( buffer ) )) > 0 ) {
1210
1211 fwrite( buffer, sizeof( char ), avail, tst_file );
1212 }
1213
1214 fclose( tst_file );
1215 }
1216
1217 free( dump_name );
1218 }
1219#endif /* DEBUG_HTTP */
1220
1221 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1222 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1223 close_rc = 0;
1224 else
1225 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001226 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001227 http_mthd, content_lgth,
1228 "bytes to URI", ctxt->uri,
1229 "failed. HTTP return code:", http_rtn );
1230
1231 xmlNanoHTTPClose( http_ctxt );
1232 xmlFree( content_type );
1233 }
1234 }
1235
1236 /* Final cleanups */
1237
1238 xmlFreeHTTPWriteCtxt( ctxt );
1239
1240 return ( close_rc );
1241}
1242
1243/**
1244 * xmlIOHTTPClosePut
1245 *
1246 * @context: The I/O context
1247 *
1248 * Close the transmit HTTP I/O channel and actually send data using a PUT
1249 * HTTP method.
1250 */
1251static int
1252xmlIOHTTPClosePut( void * ctxt ) {
1253 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1254}
1255
1256
1257/**
1258 * xmlIOHTTPClosePost
1259 *
1260 * @context: The I/O context
1261 *
1262 * Close the transmit HTTP I/O channel and actually send data using a POST
1263 * HTTP method.
1264 */
1265static int
1266xmlIOHTTPClosePost( void * ctxt ) {
1267 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1268}
1269
Owen Taylor3473f882001-02-23 17:55:21 +00001270#endif /* LIBXML_HTTP_ENABLED */
1271
1272#ifdef LIBXML_FTP_ENABLED
1273/************************************************************************
1274 * *
1275 * I/O for FTP file accesses *
1276 * *
1277 ************************************************************************/
1278/**
1279 * xmlIOFTPMatch:
1280 * @filename: the URI for matching
1281 *
1282 * check if the URI matches an FTP one
1283 *
1284 * Returns 1 if matches, 0 otherwise
1285 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001286static int
Owen Taylor3473f882001-02-23 17:55:21 +00001287xmlIOFTPMatch (const char *filename) {
1288 if (!strncmp(filename, "ftp://", 6))
1289 return(1);
1290 return(0);
1291}
1292
1293/**
1294 * xmlIOFTPOpen:
1295 * @filename: the URI for matching
1296 *
1297 * open an FTP I/O channel
1298 *
1299 * Returns an I/O context or NULL in case of error
1300 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001301static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001302xmlIOFTPOpen (const char *filename) {
1303 return(xmlNanoFTPOpen(filename));
1304}
1305
1306/**
1307 * xmlIOFTPRead:
1308 * @context: the I/O context
1309 * @buffer: where to drop data
1310 * @len: number of bytes to write
1311 *
1312 * Read @len bytes to @buffer from the I/O channel.
1313 *
1314 * Returns the number of bytes written
1315 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001316static int
Owen Taylor3473f882001-02-23 17:55:21 +00001317xmlIOFTPRead(void * context, char * buffer, int len) {
1318 return(xmlNanoFTPRead(context, &buffer[0], len));
1319}
1320
1321/**
1322 * xmlIOFTPClose:
1323 * @context: the I/O context
1324 *
1325 * Close an FTP I/O channel
1326 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001327static int
Owen Taylor3473f882001-02-23 17:55:21 +00001328xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001329 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001330}
1331#endif /* LIBXML_FTP_ENABLED */
1332
1333
1334/**
1335 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001336 * @matchFunc: the xmlInputMatchCallback
1337 * @openFunc: the xmlInputOpenCallback
1338 * @readFunc: the xmlInputReadCallback
1339 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001340 *
1341 * Register a new set of I/O callback for handling parser input.
1342 *
1343 * Returns the registered handler number or -1 in case of error
1344 */
1345int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001346xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1347 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1348 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001349 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1350 return(-1);
1351 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001352 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1353 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1354 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1355 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001356 return(xmlInputCallbackNr++);
1357}
1358
1359/**
1360 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001361 * @matchFunc: the xmlOutputMatchCallback
1362 * @openFunc: the xmlOutputOpenCallback
1363 * @writeFunc: the xmlOutputWriteCallback
1364 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001365 *
1366 * Register a new set of I/O callback for handling output.
1367 *
1368 * Returns the registered handler number or -1 in case of error
1369 */
1370int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001371xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1372 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1373 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001374 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1375 return(-1);
1376 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001377 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1378 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1379 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1380 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001381 return(xmlOutputCallbackNr++);
1382}
1383
1384/**
1385 * xmlRegisterDefaultInputCallbacks:
1386 *
1387 * Registers the default compiled-in I/O handlers.
1388 */
1389void
1390#ifdef VMS
1391xmlRegisterDefInputCallbacks
1392#else
1393xmlRegisterDefaultInputCallbacks
1394#endif
1395(void) {
1396 if (xmlInputCallbackInitialized)
1397 return;
1398
1399 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1400 xmlFileRead, xmlFileClose);
1401#ifdef HAVE_ZLIB_H
1402 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1403 xmlGzfileRead, xmlGzfileClose);
1404#endif /* HAVE_ZLIB_H */
1405
1406#ifdef LIBXML_HTTP_ENABLED
1407 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1408 xmlIOHTTPRead, xmlIOHTTPClose);
1409#endif /* LIBXML_HTTP_ENABLED */
1410
1411#ifdef LIBXML_FTP_ENABLED
1412 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1413 xmlIOFTPRead, xmlIOFTPClose);
1414#endif /* LIBXML_FTP_ENABLED */
1415 xmlInputCallbackInitialized = 1;
1416}
1417
1418/**
1419 * xmlRegisterDefaultOutputCallbacks:
1420 *
1421 * Registers the default compiled-in I/O handlers.
1422 */
1423void
1424#ifdef VMS
1425xmlRegisterDefOutputCallbacks
1426#else
1427xmlRegisterDefaultOutputCallbacks
1428#endif
1429(void) {
1430 if (xmlOutputCallbackInitialized)
1431 return;
1432
1433 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1434 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001435
1436#ifdef LIBXML_HTTP_ENABLED
1437 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1438 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1439#endif
1440
Owen Taylor3473f882001-02-23 17:55:21 +00001441/*********************************
1442 No way a-priori to distinguish between gzipped files from
1443 uncompressed ones except opening if existing then closing
1444 and saving with same compression ratio ... a pain.
1445
1446#ifdef HAVE_ZLIB_H
1447 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1448 xmlGzfileWrite, xmlGzfileClose);
1449#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001450
1451 Nor FTP PUT ....
1452#ifdef LIBXML_FTP_ENABLED
1453 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1454 xmlIOFTPWrite, xmlIOFTPClose);
1455#endif
1456 **********************************/
1457 xmlOutputCallbackInitialized = 1;
1458}
1459
Daniel Veillardf012a642001-07-23 19:10:52 +00001460#ifdef LIBXML_HTTP_ENABLED
1461/**
1462 * xmlRegisterHTTPPostCallbacks
1463 *
1464 * By default, libxml submits HTTP output requests using the "PUT" method.
1465 * Calling this method changes the HTTP output method to use the "POST"
1466 * method instead.
1467 *
1468 */
1469void
1470xmlRegisterHTTPPostCallbacks( void ) {
1471
1472 /* Register defaults if not done previously */
1473
1474 if ( xmlOutputCallbackInitialized == 0 )
1475 xmlRegisterDefaultOutputCallbacks( );
1476
1477 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1478 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1479 return;
1480}
1481#endif
1482
Owen Taylor3473f882001-02-23 17:55:21 +00001483/**
1484 * xmlAllocParserInputBuffer:
1485 * @enc: the charset encoding if known
1486 *
1487 * Create a buffered parser input for progressive parsing
1488 *
1489 * Returns the new parser input or NULL
1490 */
1491xmlParserInputBufferPtr
1492xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1493 xmlParserInputBufferPtr ret;
1494
1495 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1496 if (ret == NULL) {
1497 xmlGenericError(xmlGenericErrorContext,
1498 "xmlAllocParserInputBuffer : out of memory!\n");
1499 return(NULL);
1500 }
1501 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1502 ret->buffer = xmlBufferCreate();
1503 if (ret->buffer == NULL) {
1504 xmlFree(ret);
1505 return(NULL);
1506 }
1507 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1508 ret->encoder = xmlGetCharEncodingHandler(enc);
1509 if (ret->encoder != NULL)
1510 ret->raw = xmlBufferCreate();
1511 else
1512 ret->raw = NULL;
1513 ret->readcallback = NULL;
1514 ret->closecallback = NULL;
1515 ret->context = NULL;
1516
1517 return(ret);
1518}
1519
1520/**
1521 * xmlAllocOutputBuffer:
1522 * @encoder: the encoding converter or NULL
1523 *
1524 * Create a buffered parser output
1525 *
1526 * Returns the new parser output or NULL
1527 */
1528xmlOutputBufferPtr
1529xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1530 xmlOutputBufferPtr ret;
1531
1532 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1533 if (ret == NULL) {
1534 xmlGenericError(xmlGenericErrorContext,
1535 "xmlAllocOutputBuffer : out of memory!\n");
1536 return(NULL);
1537 }
1538 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1539 ret->buffer = xmlBufferCreate();
1540 if (ret->buffer == NULL) {
1541 xmlFree(ret);
1542 return(NULL);
1543 }
1544 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1545 ret->encoder = encoder;
1546 if (encoder != NULL) {
1547 ret->conv = xmlBufferCreateSize(4000);
1548 /*
1549 * This call is designed to initiate the encoder state
1550 */
1551 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1552 } else
1553 ret->conv = NULL;
1554 ret->writecallback = NULL;
1555 ret->closecallback = NULL;
1556 ret->context = NULL;
1557 ret->written = 0;
1558
1559 return(ret);
1560}
1561
1562/**
1563 * xmlFreeParserInputBuffer:
1564 * @in: a buffered parser input
1565 *
1566 * Free up the memory used by a buffered parser input
1567 */
1568void
1569xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1570 if (in->raw) {
1571 xmlBufferFree(in->raw);
1572 in->raw = NULL;
1573 }
1574 if (in->encoder != NULL) {
1575 xmlCharEncCloseFunc(in->encoder);
1576 }
1577 if (in->closecallback != NULL) {
1578 in->closecallback(in->context);
1579 }
1580 if (in->buffer != NULL) {
1581 xmlBufferFree(in->buffer);
1582 in->buffer = NULL;
1583 }
1584
Owen Taylor3473f882001-02-23 17:55:21 +00001585 xmlFree(in);
1586}
1587
1588/**
1589 * xmlOutputBufferClose:
1590 * @out: a buffered output
1591 *
1592 * flushes and close the output I/O channel
1593 * and free up all the associated resources
1594 *
1595 * Returns the number of byte written or -1 in case of error.
1596 */
1597int
1598xmlOutputBufferClose(xmlOutputBufferPtr out) {
1599 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001600 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001601
1602 if (out == NULL)
1603 return(-1);
1604 if (out->writecallback != NULL)
1605 xmlOutputBufferFlush(out);
1606 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001607 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001608 }
1609 written = out->written;
1610 if (out->conv) {
1611 xmlBufferFree(out->conv);
1612 out->conv = NULL;
1613 }
1614 if (out->encoder != NULL) {
1615 xmlCharEncCloseFunc(out->encoder);
1616 }
1617 if (out->buffer != NULL) {
1618 xmlBufferFree(out->buffer);
1619 out->buffer = NULL;
1620 }
1621
Owen Taylor3473f882001-02-23 17:55:21 +00001622 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001623 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001624}
1625
1626/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001627 * xmlParserInputBufferCreateFname:
1628 * @URI: a C string containing the URI or filename
1629 * @enc: the charset encoding if known
1630 *
1631 * VMS version of xmlParserInputBufferCreateFilename()
1632 *
1633 * Returns the new parser input or NULL
1634 */
1635/**
Owen Taylor3473f882001-02-23 17:55:21 +00001636 * xmlParserInputBufferCreateFilename:
1637 * @URI: a C string containing the URI or filename
1638 * @enc: the charset encoding if known
1639 *
1640 * Create a buffered parser input for the progressive parsing of a file
1641 * If filename is "-' then we use stdin as the input.
1642 * Automatic support for ZLIB/Compress compressed document is provided
1643 * by default if found at compile-time.
1644 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1645 *
1646 * Returns the new parser input or NULL
1647 */
1648xmlParserInputBufferPtr
1649#ifdef VMS
1650xmlParserInputBufferCreateFname
1651#else
1652xmlParserInputBufferCreateFilename
1653#endif
1654(const char *URI, xmlCharEncoding enc) {
1655 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001656 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001657 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001658 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001659
1660 if (xmlInputCallbackInitialized == 0)
1661 xmlRegisterDefaultInputCallbacks();
1662
1663 if (URI == NULL) return(NULL);
1664
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001665#ifdef LIBXML_CATALOG_ENABLED
1666#endif
1667
Owen Taylor3473f882001-02-23 17:55:21 +00001668 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001669 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001670 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001671 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001672 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001673 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1674 if (unescaped != NULL) {
1675 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1676 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1677 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1678 context = xmlInputCallbackTable[i].opencallback(unescaped);
1679 if (context != NULL)
1680 break;
1681 }
1682 }
1683 xmlFree(unescaped);
1684 }
1685
1686 /*
1687 * If this failed try with a non-escaped URI this may be a strange
1688 * filename
1689 */
1690 if (context == NULL) {
1691 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1692 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1693 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1694 context = xmlInputCallbackTable[i].opencallback(URI);
1695 if (context != NULL)
1696 break;
1697 }
Owen Taylor3473f882001-02-23 17:55:21 +00001698 }
1699 }
1700 if (context == NULL) {
1701 return(NULL);
1702 }
1703
1704 /*
1705 * Allocate the Input buffer front-end.
1706 */
1707 ret = xmlAllocParserInputBuffer(enc);
1708 if (ret != NULL) {
1709 ret->context = context;
1710 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1711 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1712 }
1713 return(ret);
1714}
1715
1716/**
1717 * xmlOutputBufferCreateFilename:
1718 * @URI: a C string containing the URI or filename
1719 * @encoder: the encoding converter or NULL
1720 * @compression: the compression ration (0 none, 9 max).
1721 *
1722 * Create a buffered output for the progressive saving of a file
1723 * If filename is "-' then we use stdout as the output.
1724 * Automatic support for ZLIB/Compress compressed document is provided
1725 * by default if found at compile-time.
1726 * TODO: currently if compression is set, the library only support
1727 * writing to a local file.
1728 *
1729 * Returns the new output or NULL
1730 */
1731xmlOutputBufferPtr
1732xmlOutputBufferCreateFilename(const char *URI,
1733 xmlCharEncodingHandlerPtr encoder,
1734 int compression) {
1735 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001736 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001737 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001738 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001739
Daniel Veillardf012a642001-07-23 19:10:52 +00001740 int is_http_uri = 0; /* Can't change if HTTP disabled */
1741
Owen Taylor3473f882001-02-23 17:55:21 +00001742 if (xmlOutputCallbackInitialized == 0)
1743 xmlRegisterDefaultOutputCallbacks();
1744
1745 if (URI == NULL) return(NULL);
1746
Daniel Veillardf012a642001-07-23 19:10:52 +00001747#ifdef LIBXML_HTTP_ENABLED
1748 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1749
1750 is_http_uri = xmlIOHTTPMatch( URI );
1751#endif
1752
Owen Taylor3473f882001-02-23 17:55:21 +00001753
1754 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001755 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001756 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001757 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001758 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001759 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1760 if (unescaped != NULL) {
1761#ifdef HAVE_ZLIB_H
1762 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1763 context = xmlGzfileOpenW(unescaped, compression);
1764 if (context != NULL) {
1765 ret = xmlAllocOutputBuffer(encoder);
1766 if (ret != NULL) {
1767 ret->context = context;
1768 ret->writecallback = xmlGzfileWrite;
1769 ret->closecallback = xmlGzfileClose;
1770 }
1771 xmlFree(unescaped);
1772 return(ret);
1773 }
1774 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001775#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001776 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1777 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1778 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1779#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1780 /* Need to pass compression parameter into HTTP open calls */
1781 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1782 context = xmlIOHTTPOpenW(unescaped, compression);
1783 else
1784#endif
1785 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1786 if (context != NULL)
1787 break;
1788 }
1789 }
1790 xmlFree(unescaped);
1791 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001792
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001793 /*
1794 * If this failed try with a non-escaped URI this may be a strange
1795 * filename
1796 */
1797 if (context == NULL) {
1798#ifdef HAVE_ZLIB_H
1799 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1800 context = xmlGzfileOpenW(URI, compression);
1801 if (context != NULL) {
1802 ret = xmlAllocOutputBuffer(encoder);
1803 if (ret != NULL) {
1804 ret->context = context;
1805 ret->writecallback = xmlGzfileWrite;
1806 ret->closecallback = xmlGzfileClose;
1807 }
1808 return(ret);
1809 }
1810 }
1811#endif
1812 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1813 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1814 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
1815 context = xmlOutputCallbackTable[i].opencallback(URI);
1816#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1817 /* Need to pass compression parameter into HTTP open calls */
1818 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1819 context = xmlIOHTTPOpenW(URI, compression);
1820 else
1821#endif
1822 context = xmlOutputCallbackTable[i].opencallback(URI);
1823 if (context != NULL)
1824 break;
1825 }
Owen Taylor3473f882001-02-23 17:55:21 +00001826 }
1827 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001828
Owen Taylor3473f882001-02-23 17:55:21 +00001829 if (context == NULL) {
1830 return(NULL);
1831 }
1832
1833 /*
1834 * Allocate the Output buffer front-end.
1835 */
1836 ret = xmlAllocOutputBuffer(encoder);
1837 if (ret != NULL) {
1838 ret->context = context;
1839 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1840 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1841 }
1842 return(ret);
1843}
1844
1845/**
1846 * xmlParserInputBufferCreateFile:
1847 * @file: a FILE*
1848 * @enc: the charset encoding if known
1849 *
1850 * Create a buffered parser input for the progressive parsing of a FILE *
1851 * buffered C I/O
1852 *
1853 * Returns the new parser input or NULL
1854 */
1855xmlParserInputBufferPtr
1856xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1857 xmlParserInputBufferPtr ret;
1858
1859 if (xmlInputCallbackInitialized == 0)
1860 xmlRegisterDefaultInputCallbacks();
1861
1862 if (file == NULL) return(NULL);
1863
1864 ret = xmlAllocParserInputBuffer(enc);
1865 if (ret != NULL) {
1866 ret->context = file;
1867 ret->readcallback = xmlFileRead;
1868 ret->closecallback = xmlFileFlush;
1869 }
1870
1871 return(ret);
1872}
1873
1874/**
1875 * xmlOutputBufferCreateFile:
1876 * @file: a FILE*
1877 * @encoder: the encoding converter or NULL
1878 *
1879 * Create a buffered output for the progressive saving to a FILE *
1880 * buffered C I/O
1881 *
1882 * Returns the new parser output or NULL
1883 */
1884xmlOutputBufferPtr
1885xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1886 xmlOutputBufferPtr ret;
1887
1888 if (xmlOutputCallbackInitialized == 0)
1889 xmlRegisterDefaultOutputCallbacks();
1890
1891 if (file == NULL) return(NULL);
1892
1893 ret = xmlAllocOutputBuffer(encoder);
1894 if (ret != NULL) {
1895 ret->context = file;
1896 ret->writecallback = xmlFileWrite;
1897 ret->closecallback = xmlFileFlush;
1898 }
1899
1900 return(ret);
1901}
1902
1903/**
1904 * xmlParserInputBufferCreateFd:
1905 * @fd: a file descriptor number
1906 * @enc: the charset encoding if known
1907 *
1908 * Create a buffered parser input for the progressive parsing for the input
1909 * from a file descriptor
1910 *
1911 * Returns the new parser input or NULL
1912 */
1913xmlParserInputBufferPtr
1914xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1915 xmlParserInputBufferPtr ret;
1916
1917 if (fd < 0) return(NULL);
1918
1919 ret = xmlAllocParserInputBuffer(enc);
1920 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001921 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001922 ret->readcallback = xmlFdRead;
1923 ret->closecallback = xmlFdClose;
1924 }
1925
1926 return(ret);
1927}
1928
1929/**
1930 * xmlParserInputBufferCreateMem:
1931 * @mem: the memory input
1932 * @size: the length of the memory block
1933 * @enc: the charset encoding if known
1934 *
1935 * Create a buffered parser input for the progressive parsing for the input
1936 * from a memory area.
1937 *
1938 * Returns the new parser input or NULL
1939 */
1940xmlParserInputBufferPtr
1941xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1942 xmlParserInputBufferPtr ret;
1943
1944 if (size <= 0) return(NULL);
1945 if (mem == NULL) return(NULL);
1946
1947 ret = xmlAllocParserInputBuffer(enc);
1948 if (ret != NULL) {
1949 ret->context = (void *) mem;
1950 ret->readcallback = (xmlInputReadCallback) xmlNop;
1951 ret->closecallback = NULL;
1952 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1953 }
1954
1955 return(ret);
1956}
1957
Daniel Veillarde50f3b52002-03-20 19:24:21 +00001958#ifdef HAVE_SYS_MMAN_H
1959typedef struct _xmlMMapContext xmlMMapContext;
1960typedef xmlMMapContext *xmlMMapContextPtr;
1961struct _xmlMMapContext {
1962 int fd;
1963 const char *mem;
1964 size_t size;
1965};
1966
1967/**
1968 * xmlParserInputBufferCloseMMapFile:
1969 * @ctxt: the mmaped context
1970 *
1971 * Free up the resources associated to the mmaped file
1972 */
1973static void
1974xmlParserInputBufferCloseMMapFile(xmlMMapContextPtr ctxt) {
1975 if (ctxt == NULL)
1976 return;
1977 if (ctxt->mem != (void *) MAP_FAILED)
1978 munmap((char *) ctxt->mem, ctxt->size);
1979 if (ctxt->fd >= 0)
1980 close(ctxt->fd);
1981 xmlFree(ctxt);
1982}
1983
1984/**
1985 * xmlParserInputBufferCreateMMapFile:
1986 * @fd: the descriptor associated to the mmaped file.
1987 * @base: the mmaped start
1988 * @size: the length of the memory block
1989 * @enc: the charset encoding if known
1990 *
1991 * Create a buffered parser input for the progressive parsing for the input
1992 * from a memory area.
1993 *
1994 * Returns the new parser input or NULL
1995 */
1996static xmlParserInputBufferPtr
1997xmlParserInputBufferCreateMMapFile(int fd, const char *mem, size_t size,
1998 xmlCharEncoding enc) {
1999 xmlParserInputBufferPtr ret;
2000 xmlMMapContextPtr ctxt;
2001
2002 if (fd < 0) return(NULL);
2003 if (size <= 0) return(NULL);
2004 if (mem == NULL) return(NULL);
2005
2006 ctxt = (xmlMMapContextPtr) xmlMalloc(sizeof(xmlMMapContext));
2007 if (ctxt == NULL)
2008 return(NULL);
2009 ctxt->fd = fd;
2010 ctxt->mem = mem;
2011 ctxt->size = size;
2012
2013
2014 ret = xmlAllocParserInputBuffer(enc);
2015 if (ret != NULL) {
2016 ret->context = (void *) ctxt;
2017 ret->readcallback = (xmlInputReadCallback) xmlNop;
2018 ret->closecallback = (xmlInputCloseCallback)
2019 xmlParserInputBufferCloseMMapFile;
2020 if (ret->buffer->content != NULL) {
2021 xmlFree(ret->buffer->content);
2022 }
2023 ret->buffer->alloc = XML_BUFFER_ALLOC_UNMUTABLE;
2024 ret->buffer->content = (xmlChar *) mem;
2025 ret->buffer->size = size;
2026 ret->buffer->use = size;
2027 } else {
2028 xmlFree(ctxt);
2029 return(NULL);
2030 }
2031
2032 return(ret);
2033}
2034#endif
2035
Owen Taylor3473f882001-02-23 17:55:21 +00002036/**
2037 * xmlOutputBufferCreateFd:
2038 * @fd: a file descriptor number
2039 * @encoder: the encoding converter or NULL
2040 *
2041 * Create a buffered output for the progressive saving
2042 * to a file descriptor
2043 *
2044 * Returns the new parser output or NULL
2045 */
2046xmlOutputBufferPtr
2047xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2048 xmlOutputBufferPtr ret;
2049
2050 if (fd < 0) return(NULL);
2051
2052 ret = xmlAllocOutputBuffer(encoder);
2053 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002054 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002055 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002056 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002057 }
2058
2059 return(ret);
2060}
2061
2062/**
2063 * xmlParserInputBufferCreateIO:
2064 * @ioread: an I/O read function
2065 * @ioclose: an I/O close function
2066 * @ioctx: an I/O handler
2067 * @enc: the charset encoding if known
2068 *
2069 * Create a buffered parser input for the progressive parsing for the input
2070 * from an I/O handler
2071 *
2072 * Returns the new parser input or NULL
2073 */
2074xmlParserInputBufferPtr
2075xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2076 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2077 xmlParserInputBufferPtr ret;
2078
2079 if (ioread == NULL) return(NULL);
2080
2081 ret = xmlAllocParserInputBuffer(enc);
2082 if (ret != NULL) {
2083 ret->context = (void *) ioctx;
2084 ret->readcallback = ioread;
2085 ret->closecallback = ioclose;
2086 }
2087
2088 return(ret);
2089}
2090
2091/**
2092 * xmlOutputBufferCreateIO:
2093 * @iowrite: an I/O write function
2094 * @ioclose: an I/O close function
2095 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002096 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002097 *
2098 * Create a buffered output for the progressive saving
2099 * to an I/O handler
2100 *
2101 * Returns the new parser output or NULL
2102 */
2103xmlOutputBufferPtr
2104xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2105 xmlOutputCloseCallback ioclose, void *ioctx,
2106 xmlCharEncodingHandlerPtr encoder) {
2107 xmlOutputBufferPtr ret;
2108
2109 if (iowrite == NULL) return(NULL);
2110
2111 ret = xmlAllocOutputBuffer(encoder);
2112 if (ret != NULL) {
2113 ret->context = (void *) ioctx;
2114 ret->writecallback = iowrite;
2115 ret->closecallback = ioclose;
2116 }
2117
2118 return(ret);
2119}
2120
2121/**
2122 * xmlParserInputBufferPush:
2123 * @in: a buffered parser input
2124 * @len: the size in bytes of the array.
2125 * @buf: an char array
2126 *
2127 * Push the content of the arry in the input buffer
2128 * This routine handle the I18N transcoding to internal UTF-8
2129 * This is used when operating the parser in progressive (push) mode.
2130 *
2131 * Returns the number of chars read and stored in the buffer, or -1
2132 * in case of error.
2133 */
2134int
2135xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2136 int len, const char *buf) {
2137 int nbchars = 0;
2138
2139 if (len < 0) return(0);
2140 if (in->encoder != NULL) {
2141 /*
2142 * Store the data in the incoming raw buffer
2143 */
2144 if (in->raw == NULL) {
2145 in->raw = xmlBufferCreate();
2146 }
2147 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2148
2149 /*
2150 * convert as much as possible to the parser reading buffer.
2151 */
2152 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2153 if (nbchars < 0) {
2154 xmlGenericError(xmlGenericErrorContext,
2155 "xmlParserInputBufferPush: encoder error\n");
2156 return(-1);
2157 }
2158 } else {
2159 nbchars = len;
2160 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2161 }
2162#ifdef DEBUG_INPUT
2163 xmlGenericError(xmlGenericErrorContext,
2164 "I/O: pushed %d chars, buffer %d/%d\n",
2165 nbchars, in->buffer->use, in->buffer->size);
2166#endif
2167 return(nbchars);
2168}
2169
2170/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002171 * endOfInput:
2172 *
2173 * When reading from an Input channel indicated end of file or error
2174 * don't reread from it again.
2175 */
2176static int
2177endOfInput (void * context ATTRIBUTE_UNUSED,
2178 char * buffer ATTRIBUTE_UNUSED,
2179 int len ATTRIBUTE_UNUSED) {
2180 return(0);
2181}
2182
2183/**
Owen Taylor3473f882001-02-23 17:55:21 +00002184 * xmlParserInputBufferGrow:
2185 * @in: a buffered parser input
2186 * @len: indicative value of the amount of chars to read
2187 *
2188 * Grow up the content of the input buffer, the old data are preserved
2189 * This routine handle the I18N transcoding to internal UTF-8
2190 * This routine is used when operating the parser in normal (pull) mode
2191 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002192 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002193 * onto in->buffer or in->raw
2194 *
2195 * Returns the number of chars read and stored in the buffer, or -1
2196 * in case of error.
2197 */
2198int
2199xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2200 char *buffer = NULL;
2201 int res = 0;
2202 int nbchars = 0;
2203 int buffree;
2204
2205 if ((len <= MINLEN) && (len != 4))
2206 len = MINLEN;
2207 buffree = in->buffer->size - in->buffer->use;
2208 if (buffree <= 0) {
2209 xmlGenericError(xmlGenericErrorContext,
2210 "xmlParserInputBufferGrow : buffer full !\n");
2211 return(0);
2212 }
2213 if (len > buffree)
2214 len = buffree;
2215
2216 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
2217 if (buffer == NULL) {
2218 xmlGenericError(xmlGenericErrorContext,
2219 "xmlParserInputBufferGrow : out of memory !\n");
2220 return(-1);
2221 }
2222
2223 /*
2224 * Call the read method for this I/O type.
2225 */
2226 if (in->readcallback != NULL) {
2227 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002228 if (res <= 0)
2229 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002230 } else {
2231 xmlGenericError(xmlGenericErrorContext,
2232 "xmlParserInputBufferGrow : no input !\n");
2233 xmlFree(buffer);
2234 return(-1);
2235 }
2236 if (res < 0) {
2237 perror ("read error");
2238 xmlFree(buffer);
2239 return(-1);
2240 }
2241 len = res;
2242 if (in->encoder != NULL) {
2243 /*
2244 * Store the data in the incoming raw buffer
2245 */
2246 if (in->raw == NULL) {
2247 in->raw = xmlBufferCreate();
2248 }
2249 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2250
2251 /*
2252 * convert as much as possible to the parser reading buffer.
2253 */
2254 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2255 if (nbchars < 0) {
2256 xmlGenericError(xmlGenericErrorContext,
2257 "xmlParserInputBufferGrow: encoder error\n");
2258 return(-1);
2259 }
2260 } else {
2261 nbchars = len;
2262 buffer[nbchars] = 0;
2263 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
2264 }
2265#ifdef DEBUG_INPUT
2266 xmlGenericError(xmlGenericErrorContext,
2267 "I/O: read %d chars, buffer %d/%d\n",
2268 nbchars, in->buffer->use, in->buffer->size);
2269#endif
2270 xmlFree(buffer);
2271 return(nbchars);
2272}
2273
2274/**
2275 * xmlParserInputBufferRead:
2276 * @in: a buffered parser input
2277 * @len: indicative value of the amount of chars to read
2278 *
2279 * Refresh the content of the input buffer, the old data are considered
2280 * consumed
2281 * This routine handle the I18N transcoding to internal UTF-8
2282 *
2283 * Returns the number of chars read and stored in the buffer, or -1
2284 * in case of error.
2285 */
2286int
2287xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2288 /* xmlBufferEmpty(in->buffer); */
2289 if (in->readcallback != NULL)
2290 return(xmlParserInputBufferGrow(in, len));
2291 else
2292 return(-1);
2293}
2294
2295/**
2296 * xmlOutputBufferWrite:
2297 * @out: a buffered parser output
2298 * @len: the size in bytes of the array.
2299 * @buf: an char array
2300 *
2301 * Write the content of the array in the output I/O buffer
2302 * This routine handle the I18N transcoding from internal UTF-8
2303 * The buffer is lossless, i.e. will store in case of partial
2304 * or delayed writes.
2305 *
2306 * Returns the number of chars immediately written, or -1
2307 * in case of error.
2308 */
2309int
2310xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2311 int nbchars = 0; /* number of chars to output to I/O */
2312 int ret; /* return from function call */
2313 int written = 0; /* number of char written to I/O so far */
2314 int chunk; /* number of byte curreent processed from buf */
2315
2316 if (len < 0) return(0);
2317
2318 do {
2319 chunk = len;
2320 if (chunk > 4 * MINLEN)
2321 chunk = 4 * MINLEN;
2322
2323 /*
2324 * first handle encoding stuff.
2325 */
2326 if (out->encoder != NULL) {
2327 /*
2328 * Store the data in the incoming raw buffer
2329 */
2330 if (out->conv == NULL) {
2331 out->conv = xmlBufferCreate();
2332 }
2333 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2334
2335 if ((out->buffer->use < MINLEN) && (chunk == len))
2336 goto done;
2337
2338 /*
2339 * convert as much as possible to the parser reading buffer.
2340 */
2341 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2342 if (ret < 0) {
2343 xmlGenericError(xmlGenericErrorContext,
2344 "xmlOutputBufferWrite: encoder error\n");
2345 return(-1);
2346 }
2347 nbchars = out->conv->use;
2348 } else {
2349 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2350 nbchars = out->buffer->use;
2351 }
2352 buf += chunk;
2353 len -= chunk;
2354
2355 if ((nbchars < MINLEN) && (len <= 0))
2356 goto done;
2357
2358 if (out->writecallback) {
2359 /*
2360 * second write the stuff to the I/O channel
2361 */
2362 if (out->encoder != NULL) {
2363 ret = out->writecallback(out->context,
2364 (const char *)out->conv->content, nbchars);
2365 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002366 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002367 } else {
2368 ret = out->writecallback(out->context,
2369 (const char *)out->buffer->content, nbchars);
2370 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002371 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002372 }
2373 if (ret < 0) {
2374 xmlGenericError(xmlGenericErrorContext,
2375 "I/O: error %d writing %d bytes\n", ret, nbchars);
2376 return(ret);
2377 }
2378 out->written += ret;
2379 }
2380 written += nbchars;
2381 } while (len > 0);
2382
2383done:
2384#ifdef DEBUG_INPUT
2385 xmlGenericError(xmlGenericErrorContext,
2386 "I/O: wrote %d chars\n", written);
2387#endif
2388 return(written);
2389}
2390
2391/**
2392 * xmlOutputBufferWriteString:
2393 * @out: a buffered parser output
2394 * @str: a zero terminated C string
2395 *
2396 * Write the content of the string in the output I/O buffer
2397 * This routine handle the I18N transcoding from internal UTF-8
2398 * The buffer is lossless, i.e. will store in case of partial
2399 * or delayed writes.
2400 *
2401 * Returns the number of chars immediately written, or -1
2402 * in case of error.
2403 */
2404int
2405xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2406 int len;
2407
2408 if (str == NULL)
2409 return(-1);
2410 len = strlen(str);
2411
2412 if (len > 0)
2413 return(xmlOutputBufferWrite(out, len, str));
2414 return(len);
2415}
2416
2417/**
2418 * xmlOutputBufferFlush:
2419 * @out: a buffered output
2420 *
2421 * flushes the output I/O channel
2422 *
2423 * Returns the number of byte written or -1 in case of error.
2424 */
2425int
2426xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2427 int nbchars = 0, ret = 0;
2428
2429 /*
2430 * first handle encoding stuff.
2431 */
2432 if ((out->conv != NULL) && (out->encoder != NULL)) {
2433 /*
2434 * convert as much as possible to the parser reading buffer.
2435 */
2436 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2437 if (nbchars < 0) {
2438 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002439 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002440 return(-1);
2441 }
2442 }
2443
2444 /*
2445 * second flush the stuff to the I/O channel
2446 */
2447 if ((out->conv != NULL) && (out->encoder != NULL) &&
2448 (out->writecallback != NULL)) {
2449 ret = out->writecallback(out->context,
2450 (const char *)out->conv->content, out->conv->use);
2451 if (ret >= 0)
2452 xmlBufferShrink(out->conv, ret);
2453 } else if (out->writecallback != NULL) {
2454 ret = out->writecallback(out->context,
2455 (const char *)out->buffer->content, out->buffer->use);
2456 if (ret >= 0)
2457 xmlBufferShrink(out->buffer, ret);
2458 }
2459 if (ret < 0) {
2460 xmlGenericError(xmlGenericErrorContext,
2461 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2462 return(ret);
2463 }
2464 out->written += ret;
2465
2466#ifdef DEBUG_INPUT
2467 xmlGenericError(xmlGenericErrorContext,
2468 "I/O: flushed %d chars\n", ret);
2469#endif
2470 return(ret);
2471}
2472
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002473/**
Owen Taylor3473f882001-02-23 17:55:21 +00002474 * xmlParserGetDirectory:
2475 * @filename: the path to a file
2476 *
2477 * lookup the directory for that file
2478 *
2479 * Returns a new allocated string containing the directory, or NULL.
2480 */
2481char *
2482xmlParserGetDirectory(const char *filename) {
2483 char *ret = NULL;
2484 char dir[1024];
2485 char *cur;
2486 char sep = '/';
2487
2488 if (xmlInputCallbackInitialized == 0)
2489 xmlRegisterDefaultInputCallbacks();
2490
2491 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002492#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002493 sep = '\\';
2494#endif
2495
2496 strncpy(dir, filename, 1023);
2497 dir[1023] = 0;
2498 cur = &dir[strlen(dir)];
2499 while (cur > dir) {
2500 if (*cur == sep) break;
2501 cur --;
2502 }
2503 if (*cur == sep) {
2504 if (cur == dir) dir[1] = 0;
2505 else *cur = 0;
2506 ret = xmlMemStrdup(dir);
2507 } else {
2508 if (getcwd(dir, 1024) != NULL) {
2509 dir[1023] = 0;
2510 ret = xmlMemStrdup(dir);
2511 }
2512 }
2513 return(ret);
2514}
2515
2516/****************************************************************
2517 * *
2518 * External entities loading *
2519 * *
2520 ****************************************************************/
2521
Daniel Veillarde50f3b52002-03-20 19:24:21 +00002522static const char * xmlSysIDExists(const char *URL, size_t *size) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002523#ifdef HAVE_STAT
2524 int ret;
2525 struct stat info;
2526 const char *path;
2527
2528 if (URL == NULL)
2529 return(0);
2530
2531 if (!strncmp(URL, "file://localhost", 16))
2532 path = &URL[16];
2533 else if (!strncmp(URL, "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002534#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002535 path = &URL[8];
2536#else
2537 path = &URL[7];
2538#endif
2539 } else
2540 path = URL;
2541 ret = stat(path, &info);
Daniel Veillarde50f3b52002-03-20 19:24:21 +00002542 if (ret == 0) {
2543 if (size)
2544 *size = info.st_size;
2545 return(path);
2546 }
Daniel Veillard6990bf32001-08-23 21:17:48 +00002547#endif
Daniel Veillarde50f3b52002-03-20 19:24:21 +00002548 if (size)
2549 *size = -1;
2550 return(NULL);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002551}
Daniel Veillard6990bf32001-08-23 21:17:48 +00002552
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002553/**
Owen Taylor3473f882001-02-23 17:55:21 +00002554 * xmlDefaultExternalEntityLoader:
2555 * @URL: the URL for the entity to load
2556 * @ID: the System ID for the entity to load
2557 * @ctxt: the context in which the entity is called or NULL
2558 *
2559 * By default we don't load external entitites, yet.
2560 *
2561 * Returns a new allocated xmlParserInputPtr, or NULL.
2562 */
2563static
2564xmlParserInputPtr
2565xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2566 xmlParserCtxtPtr ctxt) {
2567 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002568 xmlChar *resource = NULL;
2569#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002570 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002571#endif
Daniel Veillarde50f3b52002-03-20 19:24:21 +00002572 const char *exist;
2573 size_t length;
Owen Taylor3473f882001-02-23 17:55:21 +00002574
Daniel Veillarde50f3b52002-03-20 19:24:21 +00002575 exist = xmlSysIDExists(URL, &length);
2576#ifdef HAVE_SYS_MMAN_H
2577 /*
2578 * Shortcut, if asked for a file, the file is present, mmap it !
2579 */
2580 if ((exist != NULL) && (length > 0)) {
2581 int fd = -1;
2582 const char *base = NULL;
2583 xmlParserInputBufferPtr buf = NULL;
2584
2585 if ((fd = open(exist, O_RDONLY)) >= 0) {
2586 /*
2587 * Magic test: don't drop back native compressed content support
2588 */
2589 char tmpbuf[2];
2590 if (read(fd, tmpbuf, 2) != 2)
2591 goto failed;
2592 if ((tmpbuf[0] == 0x1F) && (tmpbuf[1] == 0x8B))
2593 goto failed;
2594
2595 base = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0);
2596 if (base != (void *) MAP_FAILED) {
2597 buf = xmlParserInputBufferCreateMMapFile(fd, base, length,
2598 XML_CHAR_ENCODING_NONE);
2599 if (buf != NULL) {
2600 ret = xmlNewInputStream(ctxt);
2601 if (ret != NULL) {
2602 ret->filename = (const char *) xmlCharStrdup(exist);
2603 ret->directory = (const char *)
2604 xmlParserGetDirectory(exist);
2605 ret->buf = buf;
2606 ret->base = ret->buf->buffer->content;
2607 ret->cur = ret->buf->buffer->content;
2608 ret->end = &ret->base[ret->buf->buffer->use];
2609 return(ret);
2610 }
2611 }
2612 }
2613 }
2614failed:
2615 if (buf != NULL)
2616 xmlFreeParserInputBuffer(buf);
2617 if (base != (void *) MAP_FAILED)
2618 munmap((char *) base, length);
2619 if (fd >= 0)
2620 close(fd);
2621 }
2622#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002623#ifdef DEBUG_EXTERNAL_ENTITIES
2624 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002625 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002626#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002627#ifdef LIBXML_CATALOG_ENABLED
2628 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002629 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002630 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002631 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002632 pref = xmlCatalogGetDefaults();
2633
Daniel Veillarde50f3b52002-03-20 19:24:21 +00002634 if ((pref != XML_CATA_ALLOW_NONE) && (exist == NULL)) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002635 /*
2636 * Do a local lookup
2637 */
2638 if ((ctxt->catalogs != NULL) &&
2639 ((pref == XML_CATA_ALLOW_ALL) ||
2640 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2641 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2642 (const xmlChar *)ID,
2643 (const xmlChar *)URL);
2644 }
2645 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002646 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002647 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002648 if ((resource == NULL) &&
2649 ((pref == XML_CATA_ALLOW_ALL) ||
2650 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002651 resource = xmlCatalogResolve((const xmlChar *)ID,
2652 (const xmlChar *)URL);
2653 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002654 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002655 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002656
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002657 /*
2658 * TODO: do an URI lookup on the reference
2659 */
Daniel Veillarde50f3b52002-03-20 19:24:21 +00002660 exist = xmlSysIDExists(URL, &length);
2661 if ((resource != NULL) && (exist == NULL)) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002662 xmlChar *tmp = NULL;
2663
2664 if ((ctxt->catalogs != NULL) &&
2665 ((pref == XML_CATA_ALLOW_ALL) ||
2666 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2667 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2668 }
2669 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002670 ((pref == XML_CATA_ALLOW_ALL) ||
2671 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002672 tmp = xmlCatalogResolveURI(resource);
2673 }
2674
2675 if (tmp != NULL) {
2676 xmlFree(resource);
2677 resource = tmp;
2678 }
2679 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002680 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002681#endif
2682
2683 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002684 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002685
2686 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002687 if (ID == NULL)
2688 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002689 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2690 (ctxt->sax->error != NULL))
2691 ctxt->sax->error(ctxt,
2692 "failed to load external entity \"%s\"\n", ID);
2693 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002694 ctxt->sax->warning(ctxt,
2695 "failed to load external entity \"%s\"\n", ID);
2696 return(NULL);
2697 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002698 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002699 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002700 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2701 (ctxt->sax->error != NULL))
2702 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002703 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002704 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002705 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002706 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002707 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002708 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002709 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002710 return(ret);
2711}
2712
2713static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2714 xmlDefaultExternalEntityLoader;
2715
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002716/**
Owen Taylor3473f882001-02-23 17:55:21 +00002717 * xmlSetExternalEntityLoader:
2718 * @f: the new entity resolver function
2719 *
2720 * Changes the defaultexternal entity resolver function for the application
2721 */
2722void
2723xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2724 xmlCurrentExternalEntityLoader = f;
2725}
2726
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002727/**
Owen Taylor3473f882001-02-23 17:55:21 +00002728 * xmlGetExternalEntityLoader:
2729 *
2730 * Get the default external entity resolver function for the application
2731 *
2732 * Returns the xmlExternalEntityLoader function pointer
2733 */
2734xmlExternalEntityLoader
2735xmlGetExternalEntityLoader(void) {
2736 return(xmlCurrentExternalEntityLoader);
2737}
2738
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002739/**
Owen Taylor3473f882001-02-23 17:55:21 +00002740 * xmlLoadExternalEntity:
2741 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002742 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002743 * @ctxt: the context in which the entity is called or NULL
2744 *
2745 * Load an external entity, note that the use of this function for
2746 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002747 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002748 *
2749 * Returns the xmlParserInputPtr or NULL
2750 */
2751xmlParserInputPtr
2752xmlLoadExternalEntity(const char *URL, const char *ID,
2753 xmlParserCtxtPtr ctxt) {
2754 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2755}
2756
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002757/************************************************************************
2758 * *
2759 * Disabling Network access *
2760 * *
2761 ************************************************************************/
2762
2763#ifdef LIBXML_CATALOG_ENABLED
2764static int
2765xmlNoNetExists(const char *URL)
2766{
2767#ifdef HAVE_STAT
2768 int ret;
2769 struct stat info;
2770 const char *path;
2771
2772 if (URL == NULL)
2773 return (0);
2774
2775 if (!xmlStrncmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
2776 path = &URL[16];
2777 else if (!xmlStrncmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002778#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002779 path = &URL[8];
2780#else
2781 path = &URL[7];
2782#endif
2783 } else
2784 path = URL;
2785 ret = stat(path, &info);
2786 if (ret == 0)
2787 return (1);
2788#endif
2789 return (0);
2790}
2791#endif
2792
2793/**
2794 * xmlNoNetExternalEntityLoader:
2795 * @URL: the URL for the entity to load
2796 * @ID: the System ID for the entity to load
2797 * @ctxt: the context in which the entity is called or NULL
2798 *
2799 * A specific entity loader disabling network accesses, though still
2800 * allowing local catalog accesses for resolution.
2801 *
2802 * Returns a new allocated xmlParserInputPtr, or NULL.
2803 */
2804xmlParserInputPtr
2805xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2806 xmlParserCtxtPtr ctxt) {
2807 xmlParserInputPtr input = NULL;
2808 xmlChar *resource = NULL;
2809
2810#ifdef LIBXML_CATALOG_ENABLED
2811 xmlCatalogAllow pref;
2812
2813 /*
2814 * If the resource doesn't exists as a file,
2815 * try to load it from the resource pointed in the catalogs
2816 */
2817 pref = xmlCatalogGetDefaults();
2818
2819 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2820 /*
2821 * Do a local lookup
2822 */
2823 if ((ctxt->catalogs != NULL) &&
2824 ((pref == XML_CATA_ALLOW_ALL) ||
2825 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2826 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2827 (const xmlChar *)ID,
2828 (const xmlChar *)URL);
2829 }
2830 /*
2831 * Try a global lookup
2832 */
2833 if ((resource == NULL) &&
2834 ((pref == XML_CATA_ALLOW_ALL) ||
2835 (pref == XML_CATA_ALLOW_GLOBAL))) {
2836 resource = xmlCatalogResolve((const xmlChar *)ID,
2837 (const xmlChar *)URL);
2838 }
2839 if ((resource == NULL) && (URL != NULL))
2840 resource = xmlStrdup((const xmlChar *) URL);
2841
2842 /*
2843 * TODO: do an URI lookup on the reference
2844 */
2845 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2846 xmlChar *tmp = NULL;
2847
2848 if ((ctxt->catalogs != NULL) &&
2849 ((pref == XML_CATA_ALLOW_ALL) ||
2850 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2851 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2852 }
2853 if ((tmp == NULL) &&
2854 ((pref == XML_CATA_ALLOW_ALL) ||
2855 (pref == XML_CATA_ALLOW_GLOBAL))) {
2856 tmp = xmlCatalogResolveURI(resource);
2857 }
2858
2859 if (tmp != NULL) {
2860 xmlFree(resource);
2861 resource = tmp;
2862 }
2863 }
2864 }
2865#endif
2866 if (resource == NULL)
2867 resource = (xmlChar *) URL;
2868
2869 if (resource != NULL) {
2870 if ((!xmlStrncasecmp((const xmlChar *) resource,
2871 (const xmlChar *) "ftp://", 6)) ||
2872 (!xmlStrncasecmp((const xmlChar *) resource,
2873 (const xmlChar *) "http://", 7))) {
2874 xmlGenericError(xmlGenericErrorContext,
2875 "Attempt to load network entity %s \n", resource);
2876
2877 if (resource != (xmlChar *) URL)
2878 xmlFree(resource);
2879 return(NULL);
2880 }
2881 }
2882 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2883 if (resource != (xmlChar *) URL)
2884 xmlFree(resource);
2885 return(input);
2886}
2887