blob: 0972e3fa0de93d5705499d55c0b708d6fe0159ab [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard344cee72001-08-20 00:08:40 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
10
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000013
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
Daniel Veillard92727042002-09-17 17:59:20 +000015#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000017#endif
18
Owen Taylor3473f882001-02-23 17:55:21 +000019
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
38
39/* Figure a portable way to know if a file is a directory. */
40#ifndef HAVE_STAT
41# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000042 /* MS C library seems to define stat and _stat. The definition
43 is identical. Still, mapping them to each other causes a warning. */
44# ifndef _MSC_VER
45# define stat(x,y) _stat(x,y)
46# endif
Owen Taylor3473f882001-02-23 17:55:21 +000047# define HAVE_STAT
48# endif
49#endif
50#ifdef HAVE_STAT
51# ifndef S_ISDIR
52# ifdef _S_ISDIR
53# define S_ISDIR(x) _S_ISDIR(x)
54# else
55# ifdef S_IFDIR
56# ifndef S_IFMT
57# ifdef _S_IFMT
58# define S_IFMT _S_IFMT
59# endif
60# endif
61# ifdef S_IFMT
62# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
63# endif
64# endif
65# endif
66# endif
67#endif
68
69#include <libxml/xmlmemory.h>
70#include <libxml/parser.h>
71#include <libxml/parserInternals.h>
72#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000073#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000074#include <libxml/nanohttp.h>
75#include <libxml/nanoftp.h>
76#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000077#ifdef LIBXML_CATALOG_ENABLED
78#include <libxml/catalog.h>
79#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000080#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000081
82#ifdef VMS
83#define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
84#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
85#endif
86
Daniel Veillardf012a642001-07-23 19:10:52 +000087/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000088/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000089/* #define DEBUG_INPUT */
90
91#ifdef DEBUG_INPUT
92#define MINLEN 40
93#else
94#define MINLEN 4000
95#endif
96
97/*
98 * Input I/O callback sets
99 */
100typedef struct _xmlInputCallback {
101 xmlInputMatchCallback matchcallback;
102 xmlInputOpenCallback opencallback;
103 xmlInputReadCallback readcallback;
104 xmlInputCloseCallback closecallback;
105} xmlInputCallback;
106
107#define MAX_INPUT_CALLBACK 15
108
Daniel Veillard22090732001-07-16 00:06:07 +0000109static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
110static int xmlInputCallbackNr = 0;
111static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000112
113/*
114 * Output I/O callback sets
115 */
116typedef struct _xmlOutputCallback {
117 xmlOutputMatchCallback matchcallback;
118 xmlOutputOpenCallback opencallback;
119 xmlOutputWriteCallback writecallback;
120 xmlOutputCloseCallback closecallback;
121} xmlOutputCallback;
122
123#define MAX_OUTPUT_CALLBACK 15
124
Daniel Veillard22090732001-07-16 00:06:07 +0000125static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
126static int xmlOutputCallbackNr = 0;
127static int xmlOutputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000128
Daniel Veillardf4862f02002-09-10 11:13:43 +0000129/************************************************************************
130 * *
131 * Handling of Windows file paths *
132 * *
133 ************************************************************************/
134
135#define IS_WINDOWS_PATH(p) \
136 ((p != NULL) && \
137 (((p[0] >= 'a') && (p[0] <= 'z')) || \
138 ((p[0] >= 'A') && (p[0] <= 'Z'))) && \
139 (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\')))
140
141
142/**
143 * xmlNormalizeWindowsPath
144 * @path: a windows path like "C:/foo/bar"
145 *
146 * Normalize a Windows path to make an URL from it
147 *
148 * Returns a new URI which must be freed by the caller or NULL
149 * in case of error
150 */
151xmlChar *
152xmlNormalizeWindowsPath(const xmlChar *path)
153{
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000154 int len, i = 0, j;
Daniel Veillardf4862f02002-09-10 11:13:43 +0000155 xmlChar *ret;
156
157 if (path == NULL)
158 return(NULL);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000159
160 len = xmlStrlen(path);
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000161 if (!IS_WINDOWS_PATH(path)) {
162 ret = xmlStrdup(path);
163 if (ret == NULL)
164 return(NULL);
165 j = 0;
166 } else {
167 ret = xmlMalloc(len + 10);
168 if (ret == NULL)
169 return(NULL);
170 ret[0] = 'f';
171 ret[1] = 'i';
172 ret[2] = 'l';
173 ret[3] = 'e';
174 ret[4] = ':';
175 ret[5] = '/';
176 ret[6] = '/';
177 ret[7] = '/';
178 j = 8;
179 }
Daniel Veillardf4862f02002-09-10 11:13:43 +0000180
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000181 while (i < len) {
Daniel Veillardf4862f02002-09-10 11:13:43 +0000182 /* TODO: UTF8 conversion + URI escaping ??? */
183 if (path[i] == '\\')
184 ret[j] = '/';
185 else
186 ret[j] = path[i];
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000187 i++;
188 j++;
Daniel Veillardf4862f02002-09-10 11:13:43 +0000189 }
190 ret[j] = 0;
Igor Zlatkovic043620e2002-10-04 13:32:07 +0000191
Daniel Veillardf4862f02002-09-10 11:13:43 +0000192 return(ret);
193}
194
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000195/**
196 * xmlCleanupInputCallbacks:
197 *
198 * clears the entire input callback table. this includes the
199 * compiled-in I/O.
200 */
201void
202xmlCleanupInputCallbacks(void)
203{
204 int i;
205
206 if (!xmlInputCallbackInitialized)
207 return;
208
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000209 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000210 xmlInputCallbackTable[i].matchcallback = NULL;
211 xmlInputCallbackTable[i].opencallback = NULL;
212 xmlInputCallbackTable[i].readcallback = NULL;
213 xmlInputCallbackTable[i].closecallback = NULL;
214 }
Daniel Veillard9e412302002-06-10 15:59:44 +0000215 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000216
217 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000218 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000219}
220
221/**
222 * xmlCleanupOutputCallbacks:
223 *
224 * clears the entire output callback table. this includes the
225 * compiled-in I/O callbacks.
226 */
227void
228xmlCleanupOutputCallbacks(void)
229{
230 int i;
231
232 if (!xmlOutputCallbackInitialized)
233 return;
234
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000235 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000236 xmlOutputCallbackTable[i].matchcallback = NULL;
237 xmlOutputCallbackTable[i].opencallback = NULL;
238 xmlOutputCallbackTable[i].writecallback = NULL;
239 xmlOutputCallbackTable[i].closecallback = NULL;
240 }
Daniel Veillard9e412302002-06-10 15:59:44 +0000241 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000242
243 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000244 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000245}
246
Owen Taylor3473f882001-02-23 17:55:21 +0000247/************************************************************************
248 * *
249 * Standard I/O for file accesses *
250 * *
251 ************************************************************************/
252
253/**
254 * xmlCheckFilename
255 * @path: the path to check
256 *
257 * function checks to see if @path is a valid source
258 * (file, socket...) for XML.
259 *
260 * if stat is not available on the target machine,
261 * returns 1. if stat fails, returns 0 (if calling
262 * stat on the filename fails, it can't be right).
263 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000264 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000265 */
266
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000267int
Owen Taylor3473f882001-02-23 17:55:21 +0000268xmlCheckFilename (const char *path)
269{
270#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000271 struct stat stat_buffer;
272
273 if (stat(path, &stat_buffer) == -1)
274 return 0;
275
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000276#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000277 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000278 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000279 }
Owen Taylor3473f882001-02-23 17:55:21 +0000280#endif
281#endif
282 return 1;
283}
284
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000285static int
Owen Taylor3473f882001-02-23 17:55:21 +0000286xmlNop(void) {
287 return(0);
288}
289
290/**
Owen Taylor3473f882001-02-23 17:55:21 +0000291 * xmlFdRead:
292 * @context: the I/O context
293 * @buffer: where to drop data
294 * @len: number of bytes to read
295 *
296 * Read @len bytes to @buffer from the I/O channel.
297 *
298 * Returns the number of bytes written
299 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000300static int
Owen Taylor3473f882001-02-23 17:55:21 +0000301xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000302 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000303}
304
305/**
306 * xmlFdWrite:
307 * @context: the I/O context
308 * @buffer: where to get data
309 * @len: number of bytes to write
310 *
311 * Write @len bytes from @buffer to the I/O channel.
312 *
313 * Returns the number of bytes written
314 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000315static int
Owen Taylor3473f882001-02-23 17:55:21 +0000316xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000317 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000318}
319
320/**
321 * xmlFdClose:
322 * @context: the I/O context
323 *
324 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000325 *
326 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000327 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000328static int
Owen Taylor3473f882001-02-23 17:55:21 +0000329xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000330 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000331}
332
333/**
334 * xmlFileMatch:
335 * @filename: the URI for matching
336 *
337 * input from FILE *
338 *
339 * Returns 1 if matches, 0 otherwise
340 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000341int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000342xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000343 return(1);
344}
345
346/**
347 * xmlFileOpen:
348 * @filename: the URI for matching
349 *
350 * input from FILE *, supports compressed input
351 * if @filename is " " then the standard input is used
352 *
353 * Returns an I/O context or NULL in case of error
354 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000355void *
Owen Taylor3473f882001-02-23 17:55:21 +0000356xmlFileOpen (const char *filename) {
357 const char *path = NULL;
358 FILE *fd;
359
360 if (!strcmp(filename, "-")) {
361 fd = stdin;
362 return((void *) fd);
363 }
364
Daniel Veillardf4862f02002-09-10 11:13:43 +0000365 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000366#if defined (_WIN32) && !defined(__CYGWIN__)
367 path = &filename[17];
368#else
Owen Taylor3473f882001-02-23 17:55:21 +0000369 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000370#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000371 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000372#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000373 path = &filename[8];
374#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000375 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000376#endif
377 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000378 path = filename;
379
380 if (path == NULL)
381 return(NULL);
382 if (!xmlCheckFilename(path))
383 return(NULL);
384
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000385#if defined(WIN32) || defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000386 fd = fopen(path, "rb");
387#else
388 fd = fopen(path, "r");
389#endif /* WIN32 */
390 return((void *) fd);
391}
392
393/**
394 * xmlFileOpenW:
395 * @filename: the URI for matching
396 *
397 * output to from FILE *,
398 * if @filename is "-" then the standard output is used
399 *
400 * Returns an I/O context or NULL in case of error
401 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000402static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000403xmlFileOpenW (const char *filename) {
404 const char *path = NULL;
405 FILE *fd;
406
407 if (!strcmp(filename, "-")) {
408 fd = stdout;
409 return((void *) fd);
410 }
411
Daniel Veillardf4862f02002-09-10 11:13:43 +0000412 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
413#if defined (_WIN32) && !defined(__CYGWIN__)
414 path = &filename[17];
415#else
Owen Taylor3473f882001-02-23 17:55:21 +0000416 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000417#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000418 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000419#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000420 path = &filename[8];
421#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000422 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000423#endif
424 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000425 path = filename;
426
427 if (path == NULL)
428 return(NULL);
429
430 fd = fopen(path, "w");
431 return((void *) fd);
432}
433
434/**
435 * xmlFileRead:
436 * @context: the I/O context
437 * @buffer: where to drop data
438 * @len: number of bytes to write
439 *
440 * Read @len bytes to @buffer from the I/O channel.
441 *
442 * Returns the number of bytes written
443 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000444int
Owen Taylor3473f882001-02-23 17:55:21 +0000445xmlFileRead (void * context, char * buffer, int len) {
446 return(fread(&buffer[0], 1, len, (FILE *) context));
447}
448
449/**
450 * xmlFileWrite:
451 * @context: the I/O context
452 * @buffer: where to drop data
453 * @len: number of bytes to write
454 *
455 * Write @len bytes from @buffer to the I/O channel.
456 *
457 * Returns the number of bytes written
458 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000459static int
Owen Taylor3473f882001-02-23 17:55:21 +0000460xmlFileWrite (void * context, const char * buffer, int len) {
461 return(fwrite(&buffer[0], 1, len, (FILE *) context));
462}
463
464/**
465 * xmlFileClose:
466 * @context: the I/O context
467 *
468 * Close an I/O channel
469 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000470int
Owen Taylor3473f882001-02-23 17:55:21 +0000471xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000472 FILE *fil;
473
474 fil = (FILE *) context;
475 if (fil == stdin)
476 return(0);
477 if (fil == stdout)
478 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000479 if (fil == stderr)
480 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000481 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000482}
483
484/**
485 * xmlFileFlush:
486 * @context: the I/O context
487 *
488 * Flush an I/O channel
489 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000490static int
Owen Taylor3473f882001-02-23 17:55:21 +0000491xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000492 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000493}
494
495#ifdef HAVE_ZLIB_H
496/************************************************************************
497 * *
498 * I/O for compressed file accesses *
499 * *
500 ************************************************************************/
501/**
502 * xmlGzfileMatch:
503 * @filename: the URI for matching
504 *
505 * input from compressed file test
506 *
507 * Returns 1 if matches, 0 otherwise
508 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000509static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000510xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000511 return(1);
512}
513
514/**
515 * xmlGzfileOpen:
516 * @filename: the URI for matching
517 *
518 * input from compressed file open
519 * if @filename is " " then the standard input is used
520 *
521 * Returns an I/O context or NULL in case of error
522 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000523static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000524xmlGzfileOpen (const char *filename) {
525 const char *path = NULL;
526 gzFile fd;
527
528 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000529 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000530 return((void *) fd);
531 }
532
Daniel Veillardf4862f02002-09-10 11:13:43 +0000533 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
534#if defined (_WIN32) && !defined(__CYGWIN__)
535 path = &filename[17];
536#else
Owen Taylor3473f882001-02-23 17:55:21 +0000537 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000538#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000539 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000540#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000541 path = &filename[8];
542#else
Owen Taylor3473f882001-02-23 17:55:21 +0000543 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000544#endif
545 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000546 path = filename;
547
548 if (path == NULL)
549 return(NULL);
550 if (!xmlCheckFilename(path))
551 return(NULL);
552
553 fd = gzopen(path, "rb");
554 return((void *) fd);
555}
556
557/**
558 * xmlGzfileOpenW:
559 * @filename: the URI for matching
560 * @compression: the compression factor (0 - 9 included)
561 *
562 * input from compressed file open
563 * if @filename is " " then the standard input is used
564 *
565 * Returns an I/O context or NULL in case of error
566 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000567static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000568xmlGzfileOpenW (const char *filename, int compression) {
569 const char *path = NULL;
570 char mode[15];
571 gzFile fd;
572
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000573 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000574 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000575 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000576 return((void *) fd);
577 }
578
Daniel Veillardf4862f02002-09-10 11:13:43 +0000579 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
580#if defined (_WIN32) && !defined(__CYGWIN__)
581 path = &filename[17];
582#else
Owen Taylor3473f882001-02-23 17:55:21 +0000583 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000584#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000585 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000586#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000587 path = &filename[8];
588#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000589 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000590#endif
591 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000592 path = filename;
593
594 if (path == NULL)
595 return(NULL);
596
597 fd = gzopen(path, mode);
598 return((void *) fd);
599}
600
601/**
602 * xmlGzfileRead:
603 * @context: the I/O context
604 * @buffer: where to drop data
605 * @len: number of bytes to write
606 *
607 * Read @len bytes to @buffer from the compressed I/O channel.
608 *
609 * Returns the number of bytes written
610 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000611static int
Owen Taylor3473f882001-02-23 17:55:21 +0000612xmlGzfileRead (void * context, char * buffer, int len) {
613 return(gzread((gzFile) context, &buffer[0], len));
614}
615
616/**
617 * xmlGzfileWrite:
618 * @context: the I/O context
619 * @buffer: where to drop data
620 * @len: number of bytes to write
621 *
622 * Write @len bytes from @buffer to the compressed I/O channel.
623 *
624 * Returns the number of bytes written
625 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000626static int
Owen Taylor3473f882001-02-23 17:55:21 +0000627xmlGzfileWrite (void * context, const char * buffer, int len) {
628 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
629}
630
631/**
632 * xmlGzfileClose:
633 * @context: the I/O context
634 *
635 * Close a compressed I/O channel
636 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000637static int
Owen Taylor3473f882001-02-23 17:55:21 +0000638xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000639 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000640}
641#endif /* HAVE_ZLIB_H */
642
643#ifdef LIBXML_HTTP_ENABLED
644/************************************************************************
645 * *
646 * I/O for HTTP file accesses *
647 * *
648 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000649
650typedef struct xmlIOHTTPWriteCtxt_
651{
652 int compression;
653
654 char * uri;
655
656 void * doc_buff;
657
658} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
659
660#ifdef HAVE_ZLIB_H
661
662#define DFLT_WBITS ( -15 )
663#define DFLT_MEM_LVL ( 8 )
664#define GZ_MAGIC1 ( 0x1f )
665#define GZ_MAGIC2 ( 0x8b )
666#define LXML_ZLIB_OS_CODE ( 0x03 )
667#define INIT_HTTP_BUFF_SIZE ( 32768 )
668#define DFLT_ZLIB_RATIO ( 5 )
669
670/*
671** Data structure and functions to work with sending compressed data
672** via HTTP.
673*/
674
675typedef struct xmlZMemBuff_
676{
677 unsigned long size;
678 unsigned long crc;
679
680 unsigned char * zbuff;
681 z_stream zctrl;
682
683} xmlZMemBuff, *xmlZMemBuffPtr;
684
685/**
686 * append_reverse_ulong
687 * @buff: Compressed memory buffer
688 * @data: Unsigned long to append
689 *
690 * Append a unsigned long in reverse byte order to the end of the
691 * memory buffer.
692 */
693static void
694append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
695
696 int idx;
697
698 if ( buff == NULL )
699 return;
700
701 /*
702 ** This is plagiarized from putLong in gzio.c (zlib source) where
703 ** the number "4" is hardcoded. If zlib is ever patched to
704 ** support 64 bit file sizes, this code would need to be patched
705 ** as well.
706 */
707
708 for ( idx = 0; idx < 4; idx++ ) {
709 *buff->zctrl.next_out = ( data & 0xff );
710 data >>= 8;
711 buff->zctrl.next_out++;
712 }
713
714 return;
715}
716
717/**
718 *
719 * xmlFreeZMemBuff
720 * @buff: The memory buffer context to clear
721 *
722 * Release all the resources associated with the compressed memory buffer.
723 */
724static void
725xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
726
727 int z_err;
728
729 if ( buff == NULL )
730 return;
731
732 xmlFree( buff->zbuff );
733 z_err = deflateEnd( &buff->zctrl );
734#ifdef DEBUG_HTTP
735 if ( z_err != Z_OK )
736 xmlGenericError( xmlGenericErrorContext,
737 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
738 z_err );
739#endif
740
741 xmlFree( buff );
742 return;
743}
744
745/**
746 * xmlCreateZMemBuff
747 *@compression: Compression value to use
748 *
749 * Create a memory buffer to hold the compressed XML document. The
750 * compressed document in memory will end up being identical to what
751 * would be created if gzopen/gzwrite/gzclose were being used to
752 * write the document to disk. The code for the header/trailer data to
753 * the compression is plagiarized from the zlib source files.
754 */
755static void *
756xmlCreateZMemBuff( int compression ) {
757
758 int z_err;
759 int hdr_lgth;
760 xmlZMemBuffPtr buff = NULL;
761
762 if ( ( compression < 1 ) || ( compression > 9 ) )
763 return ( NULL );
764
765 /* Create the control and data areas */
766
767 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
768 if ( buff == NULL ) {
769 xmlGenericError( xmlGenericErrorContext,
770 "xmlCreateZMemBuff: %s\n",
771 "Failure allocating buffer context." );
772 return ( NULL );
773 }
774
775 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
776 buff->size = INIT_HTTP_BUFF_SIZE;
777 buff->zbuff = xmlMalloc( buff->size );
778 if ( buff->zbuff == NULL ) {
779 xmlFreeZMemBuff( buff );
780 xmlGenericError( xmlGenericErrorContext,
781 "xmlCreateZMemBuff: %s\n",
782 "Failure allocating data buffer." );
783 return ( NULL );
784 }
785
786 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
787 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
788 if ( z_err != Z_OK ) {
789 xmlFreeZMemBuff( buff );
790 buff = NULL;
791 xmlGenericError( xmlGenericErrorContext,
792 "xmlCreateZMemBuff: %s %d\n",
793 "Error initializing compression context. ZLIB error:",
794 z_err );
795 return ( NULL );
796 }
797
798 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +0000799 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000800 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
801 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +0000802 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
803 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
804 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
805 buff->zctrl.avail_out = buff->size - hdr_lgth;
806
807 return ( buff );
808}
809
810/**
811 * xmlZMemBuffExtend
812 * @buff: Buffer used to compress and consolidate data.
813 * @ext_amt: Number of bytes to extend the buffer.
814 *
815 * Extend the internal buffer used to store the compressed data by the
816 * specified amount.
817 *
818 * Returns 0 on success or -1 on failure to extend the buffer. On failure
819 * the original buffer still exists at the original size.
820 */
821static int
822xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
823
824 int rc = -1;
825 size_t new_size;
826 size_t cur_used;
827
828 unsigned char * tmp_ptr = NULL;
829
830 if ( buff == NULL )
831 return ( -1 );
832
833 else if ( ext_amt == 0 )
834 return ( 0 );
835
836 cur_used = buff->zctrl.next_out - buff->zbuff;
837 new_size = buff->size + ext_amt;
838
839#ifdef DEBUG_HTTP
840 if ( cur_used > new_size )
841 xmlGenericError( xmlGenericErrorContext,
842 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
843 "Buffer overwrite detected during compressed memory",
844 "buffer extension. Overflowed by",
845 (cur_used - new_size ) );
846#endif
847
848 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
849 if ( tmp_ptr != NULL ) {
850 rc = 0;
851 buff->size = new_size;
852 buff->zbuff = tmp_ptr;
853 buff->zctrl.next_out = tmp_ptr + cur_used;
854 buff->zctrl.avail_out = new_size - cur_used;
855 }
856 else {
857 xmlGenericError( xmlGenericErrorContext,
858 "xmlZMemBuffExtend: %s %lu bytes.\n",
859 "Allocation failure extending output buffer to",
860 new_size );
861 }
862
863 return ( rc );
864}
865
866/**
867 * xmlZMemBuffAppend
868 * @buff: Buffer used to compress and consolidate data
869 * @src: Uncompressed source content to append to buffer
870 * @len: Length of source data to append to buffer
871 *
872 * Compress and append data to the internal buffer. The data buffer
873 * will be expanded if needed to store the additional data.
874 *
875 * Returns the number of bytes appended to the buffer or -1 on error.
876 */
877static int
878xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
879
880 int z_err;
881 size_t min_accept;
882
883 if ( ( buff == NULL ) || ( src == NULL ) )
884 return ( -1 );
885
886 buff->zctrl.avail_in = len;
887 buff->zctrl.next_in = (unsigned char *)src;
888 while ( buff->zctrl.avail_in > 0 ) {
889 /*
890 ** Extend the buffer prior to deflate call if a reasonable amount
891 ** of output buffer space is not available.
892 */
893 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
894 if ( buff->zctrl.avail_out <= min_accept ) {
895 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
896 return ( -1 );
897 }
898
899 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
900 if ( z_err != Z_OK ) {
901 xmlGenericError( xmlGenericErrorContext,
902 "xmlZMemBuffAppend: %s %d %s - %d",
903 "Compression error while appending",
904 len, "bytes to buffer. ZLIB error", z_err );
905 return ( -1 );
906 }
907 }
908
909 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
910
911 return ( len );
912}
913
914/**
915 * xmlZMemBuffGetContent
916 * @buff: Compressed memory content buffer
917 * @data_ref: Pointer reference to point to compressed content
918 *
919 * Flushes the compression buffers, appends gzip file trailers and
920 * returns the compressed content and length of the compressed data.
921 * NOTE: The gzip trailer code here is plagiarized from zlib source.
922 *
923 * Returns the length of the compressed data or -1 on error.
924 */
925static int
926xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
927
928 int zlgth = -1;
929 int z_err;
930
931 if ( ( buff == NULL ) || ( data_ref == NULL ) )
932 return ( -1 );
933
934 /* Need to loop until compression output buffers are flushed */
935
936 do
937 {
938 z_err = deflate( &buff->zctrl, Z_FINISH );
939 if ( z_err == Z_OK ) {
940 /* In this case Z_OK means more buffer space needed */
941
942 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
943 return ( -1 );
944 }
945 }
946 while ( z_err == Z_OK );
947
948 /* If the compression state is not Z_STREAM_END, some error occurred */
949
950 if ( z_err == Z_STREAM_END ) {
951
952 /* Need to append the gzip data trailer */
953
954 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
955 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
956 return ( -1 );
957 }
958
959 /*
960 ** For whatever reason, the CRC and length data are pushed out
961 ** in reverse byte order. So a memcpy can't be used here.
962 */
963
964 append_reverse_ulong( buff, buff->crc );
965 append_reverse_ulong( buff, buff->zctrl.total_in );
966
967 zlgth = buff->zctrl.next_out - buff->zbuff;
968 *data_ref = (char *)buff->zbuff;
969 }
970
971 else
972 xmlGenericError( xmlGenericErrorContext,
973 "xmlZMemBuffGetContent: %s - %d\n",
974 "Error flushing zlib buffers. Error code", z_err );
975
976 return ( zlgth );
977}
978#endif /* HAVE_ZLIB_H */
979
980/**
981 * xmlFreeHTTPWriteCtxt
982 * @ctxt: Context to cleanup
983 *
984 * Free allocated memory and reclaim system resources.
985 *
986 * No return value.
987 */
988static void
989xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
990{
991 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000992 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +0000993
994 if ( ctxt->doc_buff != NULL ) {
995
996#ifdef HAVE_ZLIB_H
997 if ( ctxt->compression > 0 ) {
998 xmlFreeZMemBuff( ctxt->doc_buff );
999 }
1000 else
1001#endif
1002 {
1003 xmlOutputBufferClose( ctxt->doc_buff );
1004 }
1005 }
1006
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001007 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001008 return;
1009}
1010
1011
Owen Taylor3473f882001-02-23 17:55:21 +00001012/**
1013 * xmlIOHTTPMatch:
1014 * @filename: the URI for matching
1015 *
1016 * check if the URI matches an HTTP one
1017 *
1018 * Returns 1 if matches, 0 otherwise
1019 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001020int
Owen Taylor3473f882001-02-23 17:55:21 +00001021xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001022 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001023 return(1);
1024 return(0);
1025}
1026
1027/**
1028 * xmlIOHTTPOpen:
1029 * @filename: the URI for matching
1030 *
1031 * open an HTTP I/O channel
1032 *
1033 * Returns an I/O context or NULL in case of error
1034 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001035void *
Owen Taylor3473f882001-02-23 17:55:21 +00001036xmlIOHTTPOpen (const char *filename) {
1037 return(xmlNanoHTTPOpen(filename, NULL));
1038}
1039
1040/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001041 * xmlIOHTTPOpenW
1042 * @post_uri: The destination URI for the document
1043 * @compression: The compression desired for the document.
1044 *
1045 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1046 * request. Non-static as is called from the output buffer creation routine.
1047 *
1048 * Returns an I/O context or NULL in case of error.
1049 */
1050
1051void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001052xmlIOHTTPOpenW(const char *post_uri, int compression)
1053{
Daniel Veillardf012a642001-07-23 19:10:52 +00001054
Daniel Veillard572577e2002-01-18 16:23:55 +00001055 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001056
Daniel Veillard572577e2002-01-18 16:23:55 +00001057 if (post_uri == NULL)
1058 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001059
Daniel Veillard572577e2002-01-18 16:23:55 +00001060 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1061 if (ctxt == NULL) {
1062 xmlGenericError(xmlGenericErrorContext,
1063 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
1064 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001065 }
1066
Daniel Veillard572577e2002-01-18 16:23:55 +00001067 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001068
Daniel Veillard572577e2002-01-18 16:23:55 +00001069 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1070 if (ctxt->uri == NULL) {
1071 xmlGenericError(xmlGenericErrorContext,
1072 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
1073 xmlFreeHTTPWriteCtxt(ctxt);
1074 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001075 }
1076
1077 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001078 * ** Since the document length is required for an HTTP post,
1079 * ** need to put the document into a buffer. A memory buffer
1080 * ** is being used to avoid pushing the data to disk and back.
1081 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001082
1083#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001084 if ((compression > 0) && (compression <= 9)) {
1085
1086 ctxt->compression = compression;
1087 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1088 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001089#endif
1090 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001091 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001092
Daniel Veillard572577e2002-01-18 16:23:55 +00001093 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001094 }
1095
Daniel Veillard572577e2002-01-18 16:23:55 +00001096 if (ctxt->doc_buff == NULL) {
1097 xmlFreeHTTPWriteCtxt(ctxt);
1098 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001099 }
1100
Daniel Veillard572577e2002-01-18 16:23:55 +00001101 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001102}
1103
1104/**
1105 * xmlIOHTTPDfltOpenW
1106 * @post_uri: The destination URI for this document.
1107 *
1108 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1109 * HTTP post command. This function should generally not be used as
1110 * the open callback is short circuited in xmlOutputBufferCreateFile.
1111 *
1112 * Returns a pointer to the new IO context.
1113 */
1114static void *
1115xmlIOHTTPDfltOpenW( const char * post_uri ) {
1116 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1117}
1118
1119/**
Owen Taylor3473f882001-02-23 17:55:21 +00001120 * xmlIOHTTPRead:
1121 * @context: the I/O context
1122 * @buffer: where to drop data
1123 * @len: number of bytes to write
1124 *
1125 * Read @len bytes to @buffer from the I/O channel.
1126 *
1127 * Returns the number of bytes written
1128 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001129int
Owen Taylor3473f882001-02-23 17:55:21 +00001130xmlIOHTTPRead(void * context, char * buffer, int len) {
1131 return(xmlNanoHTTPRead(context, &buffer[0], len));
1132}
1133
1134/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001135 * xmlIOHTTPWrite
1136 * @context: previously opened writing context
1137 * @buffer: data to output to temporary buffer
1138 * @len: bytes to output
1139 *
1140 * Collect data from memory buffer into a temporary file for later
1141 * processing.
1142 *
1143 * Returns number of bytes written.
1144 */
1145
1146static int
1147xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1148
1149 xmlIOHTTPWriteCtxtPtr ctxt = context;
1150
1151 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1152 return ( -1 );
1153
1154 if ( len > 0 ) {
1155
1156 /* Use gzwrite or fwrite as previously setup in the open call */
1157
1158#ifdef HAVE_ZLIB_H
1159 if ( ctxt->compression > 0 )
1160 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1161
1162 else
1163#endif
1164 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1165
1166 if ( len < 0 ) {
1167 xmlGenericError( xmlGenericErrorContext,
1168 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1169 "Error appending to internal buffer.",
1170 "Error sending document to URI",
1171 ctxt->uri );
1172 }
1173 }
1174
1175 return ( len );
1176}
1177
1178
1179/**
Owen Taylor3473f882001-02-23 17:55:21 +00001180 * xmlIOHTTPClose:
1181 * @context: the I/O context
1182 *
1183 * Close an HTTP I/O channel
1184 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001185int
Owen Taylor3473f882001-02-23 17:55:21 +00001186xmlIOHTTPClose (void * context) {
1187 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001188 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001189}
Daniel Veillardf012a642001-07-23 19:10:52 +00001190
1191/**
1192 * xmlIOHTTCloseWrite
1193 * @context: The I/O context
1194 * @http_mthd: The HTTP method to be used when sending the data
1195 *
1196 * Close the transmit HTTP I/O channel and actually send the data.
1197 */
1198static int
1199xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1200
1201 int close_rc = -1;
1202 int http_rtn = 0;
1203 int content_lgth = 0;
1204 xmlIOHTTPWriteCtxtPtr ctxt = context;
1205
1206 char * http_content = NULL;
1207 char * content_encoding = NULL;
1208 char * content_type = (char *) "text/xml";
1209 void * http_ctxt = NULL;
1210
1211 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1212 return ( -1 );
1213
1214 /* Retrieve the content from the appropriate buffer */
1215
1216#ifdef HAVE_ZLIB_H
1217
1218 if ( ctxt->compression > 0 ) {
1219 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1220 content_encoding = (char *) "Content-Encoding: gzip";
1221 }
1222 else
1223#endif
1224 {
1225 /* Pull the data out of the memory output buffer */
1226
1227 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1228 http_content = (char *)dctxt->buffer->content;
1229 content_lgth = dctxt->buffer->use;
1230 }
1231
1232 if ( http_content == NULL ) {
1233 xmlGenericError( xmlGenericErrorContext,
1234 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1235 "Error retrieving content.\nUnable to",
1236 http_mthd, "data to URI", ctxt->uri );
1237 }
1238
1239 else {
1240
1241 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1242 &content_type, content_encoding,
1243 content_lgth );
1244
1245 if ( http_ctxt != NULL ) {
1246#ifdef DEBUG_HTTP
1247 /* If testing/debugging - dump reply with request content */
1248
1249 FILE * tst_file = NULL;
1250 char buffer[ 4096 ];
1251 char * dump_name = NULL;
1252 int avail;
1253
1254 xmlGenericError( xmlGenericErrorContext,
1255 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1256 http_mthd, ctxt->uri,
1257 xmlNanoHTTPReturnCode( http_ctxt ) );
1258
1259 /*
1260 ** Since either content or reply may be gzipped,
1261 ** dump them to separate files instead of the
1262 ** standard error context.
1263 */
1264
1265 dump_name = tempnam( NULL, "lxml" );
1266 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001267 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001268
1269 tst_file = fopen( buffer, "w" );
1270 if ( tst_file != NULL ) {
1271 xmlGenericError( xmlGenericErrorContext,
1272 "Transmitted content saved in file: %s\n", buffer );
1273
1274 fwrite( http_content, sizeof( char ),
1275 content_lgth, tst_file );
1276 fclose( tst_file );
1277 }
1278
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001279 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001280 tst_file = fopen( buffer, "w" );
1281 if ( tst_file != NULL ) {
1282 xmlGenericError( xmlGenericErrorContext,
1283 "Reply content saved in file: %s\n", buffer );
1284
1285
1286 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1287 buffer, sizeof( buffer ) )) > 0 ) {
1288
1289 fwrite( buffer, sizeof( char ), avail, tst_file );
1290 }
1291
1292 fclose( tst_file );
1293 }
1294
1295 free( dump_name );
1296 }
1297#endif /* DEBUG_HTTP */
1298
1299 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1300 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1301 close_rc = 0;
1302 else
1303 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001304 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001305 http_mthd, content_lgth,
1306 "bytes to URI", ctxt->uri,
1307 "failed. HTTP return code:", http_rtn );
1308
1309 xmlNanoHTTPClose( http_ctxt );
1310 xmlFree( content_type );
1311 }
1312 }
1313
1314 /* Final cleanups */
1315
1316 xmlFreeHTTPWriteCtxt( ctxt );
1317
1318 return ( close_rc );
1319}
1320
1321/**
1322 * xmlIOHTTPClosePut
1323 *
1324 * @context: The I/O context
1325 *
1326 * Close the transmit HTTP I/O channel and actually send data using a PUT
1327 * HTTP method.
1328 */
1329static int
1330xmlIOHTTPClosePut( void * ctxt ) {
1331 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1332}
1333
1334
1335/**
1336 * xmlIOHTTPClosePost
1337 *
1338 * @context: The I/O context
1339 *
1340 * Close the transmit HTTP I/O channel and actually send data using a POST
1341 * HTTP method.
1342 */
1343static int
1344xmlIOHTTPClosePost( void * ctxt ) {
1345 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1346}
1347
Owen Taylor3473f882001-02-23 17:55:21 +00001348#endif /* LIBXML_HTTP_ENABLED */
1349
1350#ifdef LIBXML_FTP_ENABLED
1351/************************************************************************
1352 * *
1353 * I/O for FTP file accesses *
1354 * *
1355 ************************************************************************/
1356/**
1357 * xmlIOFTPMatch:
1358 * @filename: the URI for matching
1359 *
1360 * check if the URI matches an FTP one
1361 *
1362 * Returns 1 if matches, 0 otherwise
1363 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001364int
Owen Taylor3473f882001-02-23 17:55:21 +00001365xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001366 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001367 return(1);
1368 return(0);
1369}
1370
1371/**
1372 * xmlIOFTPOpen:
1373 * @filename: the URI for matching
1374 *
1375 * open an FTP I/O channel
1376 *
1377 * Returns an I/O context or NULL in case of error
1378 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001379void *
Owen Taylor3473f882001-02-23 17:55:21 +00001380xmlIOFTPOpen (const char *filename) {
1381 return(xmlNanoFTPOpen(filename));
1382}
1383
1384/**
1385 * xmlIOFTPRead:
1386 * @context: the I/O context
1387 * @buffer: where to drop data
1388 * @len: number of bytes to write
1389 *
1390 * Read @len bytes to @buffer from the I/O channel.
1391 *
1392 * Returns the number of bytes written
1393 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001394int
Owen Taylor3473f882001-02-23 17:55:21 +00001395xmlIOFTPRead(void * context, char * buffer, int len) {
1396 return(xmlNanoFTPRead(context, &buffer[0], len));
1397}
1398
1399/**
1400 * xmlIOFTPClose:
1401 * @context: the I/O context
1402 *
1403 * Close an FTP I/O channel
1404 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001405int
Owen Taylor3473f882001-02-23 17:55:21 +00001406xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001407 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001408}
1409#endif /* LIBXML_FTP_ENABLED */
1410
1411
1412/**
1413 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001414 * @matchFunc: the xmlInputMatchCallback
1415 * @openFunc: the xmlInputOpenCallback
1416 * @readFunc: the xmlInputReadCallback
1417 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001418 *
1419 * Register a new set of I/O callback for handling parser input.
1420 *
1421 * Returns the registered handler number or -1 in case of error
1422 */
1423int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001424xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1425 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1426 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001427 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1428 return(-1);
1429 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001430 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1431 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1432 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1433 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001434 return(xmlInputCallbackNr++);
1435}
1436
1437/**
1438 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001439 * @matchFunc: the xmlOutputMatchCallback
1440 * @openFunc: the xmlOutputOpenCallback
1441 * @writeFunc: the xmlOutputWriteCallback
1442 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001443 *
1444 * Register a new set of I/O callback for handling output.
1445 *
1446 * Returns the registered handler number or -1 in case of error
1447 */
1448int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001449xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1450 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1451 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001452 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1453 return(-1);
1454 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001455 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1456 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1457 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1458 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001459 return(xmlOutputCallbackNr++);
1460}
1461
1462/**
1463 * xmlRegisterDefaultInputCallbacks:
1464 *
1465 * Registers the default compiled-in I/O handlers.
1466 */
1467void
1468#ifdef VMS
1469xmlRegisterDefInputCallbacks
1470#else
1471xmlRegisterDefaultInputCallbacks
1472#endif
1473(void) {
1474 if (xmlInputCallbackInitialized)
1475 return;
1476
1477 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1478 xmlFileRead, xmlFileClose);
1479#ifdef HAVE_ZLIB_H
1480 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1481 xmlGzfileRead, xmlGzfileClose);
1482#endif /* HAVE_ZLIB_H */
1483
1484#ifdef LIBXML_HTTP_ENABLED
1485 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1486 xmlIOHTTPRead, xmlIOHTTPClose);
1487#endif /* LIBXML_HTTP_ENABLED */
1488
1489#ifdef LIBXML_FTP_ENABLED
1490 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1491 xmlIOFTPRead, xmlIOFTPClose);
1492#endif /* LIBXML_FTP_ENABLED */
1493 xmlInputCallbackInitialized = 1;
1494}
1495
1496/**
1497 * xmlRegisterDefaultOutputCallbacks:
1498 *
1499 * Registers the default compiled-in I/O handlers.
1500 */
1501void
1502#ifdef VMS
1503xmlRegisterDefOutputCallbacks
1504#else
1505xmlRegisterDefaultOutputCallbacks
1506#endif
1507(void) {
1508 if (xmlOutputCallbackInitialized)
1509 return;
1510
1511 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1512 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001513
1514#ifdef LIBXML_HTTP_ENABLED
1515 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1516 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1517#endif
1518
Owen Taylor3473f882001-02-23 17:55:21 +00001519/*********************************
1520 No way a-priori to distinguish between gzipped files from
1521 uncompressed ones except opening if existing then closing
1522 and saving with same compression ratio ... a pain.
1523
1524#ifdef HAVE_ZLIB_H
1525 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1526 xmlGzfileWrite, xmlGzfileClose);
1527#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001528
1529 Nor FTP PUT ....
1530#ifdef LIBXML_FTP_ENABLED
1531 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1532 xmlIOFTPWrite, xmlIOFTPClose);
1533#endif
1534 **********************************/
1535 xmlOutputCallbackInitialized = 1;
1536}
1537
Daniel Veillardf012a642001-07-23 19:10:52 +00001538#ifdef LIBXML_HTTP_ENABLED
1539/**
1540 * xmlRegisterHTTPPostCallbacks
1541 *
1542 * By default, libxml submits HTTP output requests using the "PUT" method.
1543 * Calling this method changes the HTTP output method to use the "POST"
1544 * method instead.
1545 *
1546 */
1547void
1548xmlRegisterHTTPPostCallbacks( void ) {
1549
1550 /* Register defaults if not done previously */
1551
1552 if ( xmlOutputCallbackInitialized == 0 )
1553 xmlRegisterDefaultOutputCallbacks( );
1554
1555 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1556 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1557 return;
1558}
1559#endif
1560
Owen Taylor3473f882001-02-23 17:55:21 +00001561/**
1562 * xmlAllocParserInputBuffer:
1563 * @enc: the charset encoding if known
1564 *
1565 * Create a buffered parser input for progressive parsing
1566 *
1567 * Returns the new parser input or NULL
1568 */
1569xmlParserInputBufferPtr
1570xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1571 xmlParserInputBufferPtr ret;
1572
1573 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1574 if (ret == NULL) {
1575 xmlGenericError(xmlGenericErrorContext,
1576 "xmlAllocParserInputBuffer : out of memory!\n");
1577 return(NULL);
1578 }
1579 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1580 ret->buffer = xmlBufferCreate();
1581 if (ret->buffer == NULL) {
1582 xmlFree(ret);
1583 return(NULL);
1584 }
1585 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1586 ret->encoder = xmlGetCharEncodingHandler(enc);
1587 if (ret->encoder != NULL)
1588 ret->raw = xmlBufferCreate();
1589 else
1590 ret->raw = NULL;
1591 ret->readcallback = NULL;
1592 ret->closecallback = NULL;
1593 ret->context = NULL;
1594
1595 return(ret);
1596}
1597
1598/**
1599 * xmlAllocOutputBuffer:
1600 * @encoder: the encoding converter or NULL
1601 *
1602 * Create a buffered parser output
1603 *
1604 * Returns the new parser output or NULL
1605 */
1606xmlOutputBufferPtr
1607xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1608 xmlOutputBufferPtr ret;
1609
1610 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1611 if (ret == NULL) {
1612 xmlGenericError(xmlGenericErrorContext,
1613 "xmlAllocOutputBuffer : out of memory!\n");
1614 return(NULL);
1615 }
1616 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1617 ret->buffer = xmlBufferCreate();
1618 if (ret->buffer == NULL) {
1619 xmlFree(ret);
1620 return(NULL);
1621 }
1622 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1623 ret->encoder = encoder;
1624 if (encoder != NULL) {
1625 ret->conv = xmlBufferCreateSize(4000);
1626 /*
1627 * This call is designed to initiate the encoder state
1628 */
1629 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1630 } else
1631 ret->conv = NULL;
1632 ret->writecallback = NULL;
1633 ret->closecallback = NULL;
1634 ret->context = NULL;
1635 ret->written = 0;
1636
1637 return(ret);
1638}
1639
1640/**
1641 * xmlFreeParserInputBuffer:
1642 * @in: a buffered parser input
1643 *
1644 * Free up the memory used by a buffered parser input
1645 */
1646void
1647xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1648 if (in->raw) {
1649 xmlBufferFree(in->raw);
1650 in->raw = NULL;
1651 }
1652 if (in->encoder != NULL) {
1653 xmlCharEncCloseFunc(in->encoder);
1654 }
1655 if (in->closecallback != NULL) {
1656 in->closecallback(in->context);
1657 }
1658 if (in->buffer != NULL) {
1659 xmlBufferFree(in->buffer);
1660 in->buffer = NULL;
1661 }
1662
Owen Taylor3473f882001-02-23 17:55:21 +00001663 xmlFree(in);
1664}
1665
1666/**
1667 * xmlOutputBufferClose:
1668 * @out: a buffered output
1669 *
1670 * flushes and close the output I/O channel
1671 * and free up all the associated resources
1672 *
1673 * Returns the number of byte written or -1 in case of error.
1674 */
1675int
1676xmlOutputBufferClose(xmlOutputBufferPtr out) {
1677 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001678 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001679
1680 if (out == NULL)
1681 return(-1);
1682 if (out->writecallback != NULL)
1683 xmlOutputBufferFlush(out);
1684 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001685 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001686 }
1687 written = out->written;
1688 if (out->conv) {
1689 xmlBufferFree(out->conv);
1690 out->conv = NULL;
1691 }
1692 if (out->encoder != NULL) {
1693 xmlCharEncCloseFunc(out->encoder);
1694 }
1695 if (out->buffer != NULL) {
1696 xmlBufferFree(out->buffer);
1697 out->buffer = NULL;
1698 }
1699
Owen Taylor3473f882001-02-23 17:55:21 +00001700 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001701 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001702}
1703
1704/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001705 * xmlParserInputBufferCreateFname:
1706 * @URI: a C string containing the URI or filename
1707 * @enc: the charset encoding if known
1708 *
1709 * VMS version of xmlParserInputBufferCreateFilename()
1710 *
1711 * Returns the new parser input or NULL
1712 */
1713/**
Owen Taylor3473f882001-02-23 17:55:21 +00001714 * xmlParserInputBufferCreateFilename:
1715 * @URI: a C string containing the URI or filename
1716 * @enc: the charset encoding if known
1717 *
1718 * Create a buffered parser input for the progressive parsing of a file
1719 * If filename is "-' then we use stdin as the input.
1720 * Automatic support for ZLIB/Compress compressed document is provided
1721 * by default if found at compile-time.
1722 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1723 *
1724 * Returns the new parser input or NULL
1725 */
1726xmlParserInputBufferPtr
1727#ifdef VMS
1728xmlParserInputBufferCreateFname
1729#else
1730xmlParserInputBufferCreateFilename
1731#endif
1732(const char *URI, xmlCharEncoding enc) {
1733 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001734 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001735 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001736 char *unescaped;
Daniel Veillardf4862f02002-09-10 11:13:43 +00001737 char *normalized;
Owen Taylor3473f882001-02-23 17:55:21 +00001738
1739 if (xmlInputCallbackInitialized == 0)
1740 xmlRegisterDefaultInputCallbacks();
1741
1742 if (URI == NULL) return(NULL);
Daniel Veillardf4862f02002-09-10 11:13:43 +00001743 normalized = (char *) xmlNormalizeWindowsPath((const xmlChar *)URI);
1744 if (normalized == NULL) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001745
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001746#ifdef LIBXML_CATALOG_ENABLED
1747#endif
1748
Owen Taylor3473f882001-02-23 17:55:21 +00001749 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001750 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001751 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001752 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001753 */
Daniel Veillardf4862f02002-09-10 11:13:43 +00001754 unescaped = xmlURIUnescapeString((char *) normalized, 0, NULL);
Daniel Veillard388236f2001-07-08 18:35:48 +00001755 if (unescaped != NULL) {
1756 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1757 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1758 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1759 context = xmlInputCallbackTable[i].opencallback(unescaped);
1760 if (context != NULL)
1761 break;
1762 }
1763 }
1764 xmlFree(unescaped);
1765 }
1766
1767 /*
1768 * If this failed try with a non-escaped URI this may be a strange
1769 * filename
1770 */
1771 if (context == NULL) {
1772 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1773 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1774 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardf4862f02002-09-10 11:13:43 +00001775 context = xmlInputCallbackTable[i].opencallback(normalized);
Daniel Veillard388236f2001-07-08 18:35:48 +00001776 if (context != NULL)
1777 break;
1778 }
Owen Taylor3473f882001-02-23 17:55:21 +00001779 }
1780 }
Daniel Veillardf4862f02002-09-10 11:13:43 +00001781 xmlFree(normalized);
Owen Taylor3473f882001-02-23 17:55:21 +00001782 if (context == NULL) {
1783 return(NULL);
1784 }
1785
1786 /*
1787 * Allocate the Input buffer front-end.
1788 */
1789 ret = xmlAllocParserInputBuffer(enc);
1790 if (ret != NULL) {
1791 ret->context = context;
1792 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1793 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1794 }
1795 return(ret);
1796}
1797
1798/**
1799 * xmlOutputBufferCreateFilename:
1800 * @URI: a C string containing the URI or filename
1801 * @encoder: the encoding converter or NULL
1802 * @compression: the compression ration (0 none, 9 max).
1803 *
1804 * Create a buffered output for the progressive saving of a file
1805 * If filename is "-' then we use stdout as the output.
1806 * Automatic support for ZLIB/Compress compressed document is provided
1807 * by default if found at compile-time.
1808 * TODO: currently if compression is set, the library only support
1809 * writing to a local file.
1810 *
1811 * Returns the new output or NULL
1812 */
1813xmlOutputBufferPtr
1814xmlOutputBufferCreateFilename(const char *URI,
1815 xmlCharEncodingHandlerPtr encoder,
1816 int compression) {
1817 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001818 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001819 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001820 char *unescaped;
Daniel Veillardf4862f02002-09-10 11:13:43 +00001821 char *normalized;
Owen Taylor3473f882001-02-23 17:55:21 +00001822
Daniel Veillardf012a642001-07-23 19:10:52 +00001823 int is_http_uri = 0; /* Can't change if HTTP disabled */
1824
Owen Taylor3473f882001-02-23 17:55:21 +00001825 if (xmlOutputCallbackInitialized == 0)
1826 xmlRegisterDefaultOutputCallbacks();
1827
1828 if (URI == NULL) return(NULL);
Daniel Veillardf4862f02002-09-10 11:13:43 +00001829 normalized = (char *) xmlNormalizeWindowsPath((const xmlChar *)URI);
1830 if (normalized == NULL) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001831
Daniel Veillardf012a642001-07-23 19:10:52 +00001832#ifdef LIBXML_HTTP_ENABLED
1833 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1834
Daniel Veillardf4862f02002-09-10 11:13:43 +00001835 is_http_uri = xmlIOHTTPMatch( normalized );
Daniel Veillardf012a642001-07-23 19:10:52 +00001836#endif
1837
Owen Taylor3473f882001-02-23 17:55:21 +00001838
1839 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001840 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001841 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001842 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001843 */
Daniel Veillardf4862f02002-09-10 11:13:43 +00001844 unescaped = xmlURIUnescapeString(normalized, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001845 if (unescaped != NULL) {
1846#ifdef HAVE_ZLIB_H
1847 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1848 context = xmlGzfileOpenW(unescaped, compression);
1849 if (context != NULL) {
1850 ret = xmlAllocOutputBuffer(encoder);
1851 if (ret != NULL) {
1852 ret->context = context;
1853 ret->writecallback = xmlGzfileWrite;
1854 ret->closecallback = xmlGzfileClose;
1855 }
1856 xmlFree(unescaped);
Daniel Veillardf4862f02002-09-10 11:13:43 +00001857 xmlFree(normalized);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001858 return(ret);
1859 }
1860 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001861#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001862 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1863 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1864 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1865#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1866 /* Need to pass compression parameter into HTTP open calls */
1867 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1868 context = xmlIOHTTPOpenW(unescaped, compression);
1869 else
1870#endif
1871 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1872 if (context != NULL)
1873 break;
1874 }
1875 }
1876 xmlFree(unescaped);
1877 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001878
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001879 /*
1880 * If this failed try with a non-escaped URI this may be a strange
1881 * filename
1882 */
1883 if (context == NULL) {
1884#ifdef HAVE_ZLIB_H
1885 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Daniel Veillardf4862f02002-09-10 11:13:43 +00001886 context = xmlGzfileOpenW(normalized, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001887 if (context != NULL) {
1888 ret = xmlAllocOutputBuffer(encoder);
1889 if (ret != NULL) {
1890 ret->context = context;
1891 ret->writecallback = xmlGzfileWrite;
1892 ret->closecallback = xmlGzfileClose;
1893 }
Daniel Veillardf4862f02002-09-10 11:13:43 +00001894 xmlFree(normalized);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001895 return(ret);
1896 }
1897 }
1898#endif
1899 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1900 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Daniel Veillardf4862f02002-09-10 11:13:43 +00001901 (xmlOutputCallbackTable[i].matchcallback(normalized) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001902#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1903 /* Need to pass compression parameter into HTTP open calls */
1904 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1905 context = xmlIOHTTPOpenW(URI, compression);
1906 else
1907#endif
1908 context = xmlOutputCallbackTable[i].opencallback(URI);
1909 if (context != NULL)
1910 break;
1911 }
Owen Taylor3473f882001-02-23 17:55:21 +00001912 }
1913 }
Daniel Veillardf4862f02002-09-10 11:13:43 +00001914 xmlFree(normalized);
Daniel Veillardf012a642001-07-23 19:10:52 +00001915
Owen Taylor3473f882001-02-23 17:55:21 +00001916 if (context == NULL) {
1917 return(NULL);
1918 }
1919
1920 /*
1921 * Allocate the Output buffer front-end.
1922 */
1923 ret = xmlAllocOutputBuffer(encoder);
1924 if (ret != NULL) {
1925 ret->context = context;
1926 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1927 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1928 }
1929 return(ret);
1930}
1931
1932/**
1933 * xmlParserInputBufferCreateFile:
1934 * @file: a FILE*
1935 * @enc: the charset encoding if known
1936 *
1937 * Create a buffered parser input for the progressive parsing of a FILE *
1938 * buffered C I/O
1939 *
1940 * Returns the new parser input or NULL
1941 */
1942xmlParserInputBufferPtr
1943xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1944 xmlParserInputBufferPtr ret;
1945
1946 if (xmlInputCallbackInitialized == 0)
1947 xmlRegisterDefaultInputCallbacks();
1948
1949 if (file == NULL) return(NULL);
1950
1951 ret = xmlAllocParserInputBuffer(enc);
1952 if (ret != NULL) {
1953 ret->context = file;
1954 ret->readcallback = xmlFileRead;
1955 ret->closecallback = xmlFileFlush;
1956 }
1957
1958 return(ret);
1959}
1960
1961/**
1962 * xmlOutputBufferCreateFile:
1963 * @file: a FILE*
1964 * @encoder: the encoding converter or NULL
1965 *
1966 * Create a buffered output for the progressive saving to a FILE *
1967 * buffered C I/O
1968 *
1969 * Returns the new parser output or NULL
1970 */
1971xmlOutputBufferPtr
1972xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1973 xmlOutputBufferPtr ret;
1974
1975 if (xmlOutputCallbackInitialized == 0)
1976 xmlRegisterDefaultOutputCallbacks();
1977
1978 if (file == NULL) return(NULL);
1979
1980 ret = xmlAllocOutputBuffer(encoder);
1981 if (ret != NULL) {
1982 ret->context = file;
1983 ret->writecallback = xmlFileWrite;
1984 ret->closecallback = xmlFileFlush;
1985 }
1986
1987 return(ret);
1988}
1989
1990/**
1991 * xmlParserInputBufferCreateFd:
1992 * @fd: a file descriptor number
1993 * @enc: the charset encoding if known
1994 *
1995 * Create a buffered parser input for the progressive parsing for the input
1996 * from a file descriptor
1997 *
1998 * Returns the new parser input or NULL
1999 */
2000xmlParserInputBufferPtr
2001xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2002 xmlParserInputBufferPtr ret;
2003
2004 if (fd < 0) return(NULL);
2005
2006 ret = xmlAllocParserInputBuffer(enc);
2007 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002008 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002009 ret->readcallback = xmlFdRead;
2010 ret->closecallback = xmlFdClose;
2011 }
2012
2013 return(ret);
2014}
2015
2016/**
2017 * xmlParserInputBufferCreateMem:
2018 * @mem: the memory input
2019 * @size: the length of the memory block
2020 * @enc: the charset encoding if known
2021 *
2022 * Create a buffered parser input for the progressive parsing for the input
2023 * from a memory area.
2024 *
2025 * Returns the new parser input or NULL
2026 */
2027xmlParserInputBufferPtr
2028xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2029 xmlParserInputBufferPtr ret;
2030
2031 if (size <= 0) return(NULL);
2032 if (mem == NULL) return(NULL);
2033
2034 ret = xmlAllocParserInputBuffer(enc);
2035 if (ret != NULL) {
2036 ret->context = (void *) mem;
2037 ret->readcallback = (xmlInputReadCallback) xmlNop;
2038 ret->closecallback = NULL;
2039 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2040 }
2041
2042 return(ret);
2043}
2044
2045/**
2046 * xmlOutputBufferCreateFd:
2047 * @fd: a file descriptor number
2048 * @encoder: the encoding converter or NULL
2049 *
2050 * Create a buffered output for the progressive saving
2051 * to a file descriptor
2052 *
2053 * Returns the new parser output or NULL
2054 */
2055xmlOutputBufferPtr
2056xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2057 xmlOutputBufferPtr ret;
2058
2059 if (fd < 0) return(NULL);
2060
2061 ret = xmlAllocOutputBuffer(encoder);
2062 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002063 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002064 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002065 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002066 }
2067
2068 return(ret);
2069}
2070
2071/**
2072 * xmlParserInputBufferCreateIO:
2073 * @ioread: an I/O read function
2074 * @ioclose: an I/O close function
2075 * @ioctx: an I/O handler
2076 * @enc: the charset encoding if known
2077 *
2078 * Create a buffered parser input for the progressive parsing for the input
2079 * from an I/O handler
2080 *
2081 * Returns the new parser input or NULL
2082 */
2083xmlParserInputBufferPtr
2084xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2085 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2086 xmlParserInputBufferPtr ret;
2087
2088 if (ioread == NULL) return(NULL);
2089
2090 ret = xmlAllocParserInputBuffer(enc);
2091 if (ret != NULL) {
2092 ret->context = (void *) ioctx;
2093 ret->readcallback = ioread;
2094 ret->closecallback = ioclose;
2095 }
2096
2097 return(ret);
2098}
2099
2100/**
2101 * xmlOutputBufferCreateIO:
2102 * @iowrite: an I/O write function
2103 * @ioclose: an I/O close function
2104 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002105 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002106 *
2107 * Create a buffered output for the progressive saving
2108 * to an I/O handler
2109 *
2110 * Returns the new parser output or NULL
2111 */
2112xmlOutputBufferPtr
2113xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2114 xmlOutputCloseCallback ioclose, void *ioctx,
2115 xmlCharEncodingHandlerPtr encoder) {
2116 xmlOutputBufferPtr ret;
2117
2118 if (iowrite == NULL) return(NULL);
2119
2120 ret = xmlAllocOutputBuffer(encoder);
2121 if (ret != NULL) {
2122 ret->context = (void *) ioctx;
2123 ret->writecallback = iowrite;
2124 ret->closecallback = ioclose;
2125 }
2126
2127 return(ret);
2128}
2129
2130/**
2131 * xmlParserInputBufferPush:
2132 * @in: a buffered parser input
2133 * @len: the size in bytes of the array.
2134 * @buf: an char array
2135 *
2136 * Push the content of the arry in the input buffer
2137 * This routine handle the I18N transcoding to internal UTF-8
2138 * This is used when operating the parser in progressive (push) mode.
2139 *
2140 * Returns the number of chars read and stored in the buffer, or -1
2141 * in case of error.
2142 */
2143int
2144xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2145 int len, const char *buf) {
2146 int nbchars = 0;
2147
2148 if (len < 0) return(0);
2149 if (in->encoder != NULL) {
2150 /*
2151 * Store the data in the incoming raw buffer
2152 */
2153 if (in->raw == NULL) {
2154 in->raw = xmlBufferCreate();
2155 }
2156 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2157
2158 /*
2159 * convert as much as possible to the parser reading buffer.
2160 */
2161 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2162 if (nbchars < 0) {
2163 xmlGenericError(xmlGenericErrorContext,
2164 "xmlParserInputBufferPush: encoder error\n");
2165 return(-1);
2166 }
2167 } else {
2168 nbchars = len;
2169 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2170 }
2171#ifdef DEBUG_INPUT
2172 xmlGenericError(xmlGenericErrorContext,
2173 "I/O: pushed %d chars, buffer %d/%d\n",
2174 nbchars, in->buffer->use, in->buffer->size);
2175#endif
2176 return(nbchars);
2177}
2178
2179/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002180 * endOfInput:
2181 *
2182 * When reading from an Input channel indicated end of file or error
2183 * don't reread from it again.
2184 */
2185static int
2186endOfInput (void * context ATTRIBUTE_UNUSED,
2187 char * buffer ATTRIBUTE_UNUSED,
2188 int len ATTRIBUTE_UNUSED) {
2189 return(0);
2190}
2191
2192/**
Owen Taylor3473f882001-02-23 17:55:21 +00002193 * xmlParserInputBufferGrow:
2194 * @in: a buffered parser input
2195 * @len: indicative value of the amount of chars to read
2196 *
2197 * Grow up the content of the input buffer, the old data are preserved
2198 * This routine handle the I18N transcoding to internal UTF-8
2199 * This routine is used when operating the parser in normal (pull) mode
2200 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002201 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002202 * onto in->buffer or in->raw
2203 *
2204 * Returns the number of chars read and stored in the buffer, or -1
2205 * in case of error.
2206 */
2207int
2208xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2209 char *buffer = NULL;
2210 int res = 0;
2211 int nbchars = 0;
2212 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002213 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002214
2215 if ((len <= MINLEN) && (len != 4))
2216 len = MINLEN;
2217 buffree = in->buffer->size - in->buffer->use;
2218 if (buffree <= 0) {
2219 xmlGenericError(xmlGenericErrorContext,
2220 "xmlParserInputBufferGrow : buffer full !\n");
2221 return(0);
2222 }
2223 if (len > buffree)
2224 len = buffree;
2225
Daniel Veillarde5354492002-05-16 08:43:22 +00002226 needSize = in->buffer->use + len + 1;
2227 if (needSize > in->buffer->size){
2228 if (!xmlBufferResize(in->buffer, needSize)){
2229 xmlGenericError(xmlGenericErrorContext,
2230 "xmlBufferAdd : out of memory!\n");
2231 return(0);
2232 }
Owen Taylor3473f882001-02-23 17:55:21 +00002233 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002234 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002235
2236 /*
2237 * Call the read method for this I/O type.
2238 */
2239 if (in->readcallback != NULL) {
2240 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002241 if (res <= 0)
2242 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002243 } else {
2244 xmlGenericError(xmlGenericErrorContext,
2245 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002246 return(-1);
2247 }
2248 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002249 return(-1);
2250 }
2251 len = res;
2252 if (in->encoder != NULL) {
2253 /*
2254 * Store the data in the incoming raw buffer
2255 */
2256 if (in->raw == NULL) {
2257 in->raw = xmlBufferCreate();
2258 }
2259 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2260
2261 /*
2262 * convert as much as possible to the parser reading buffer.
2263 */
2264 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2265 if (nbchars < 0) {
2266 xmlGenericError(xmlGenericErrorContext,
2267 "xmlParserInputBufferGrow: encoder error\n");
2268 return(-1);
2269 }
2270 } else {
2271 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002272 in->buffer->use += nbchars;
2273 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002274 }
2275#ifdef DEBUG_INPUT
2276 xmlGenericError(xmlGenericErrorContext,
2277 "I/O: read %d chars, buffer %d/%d\n",
2278 nbchars, in->buffer->use, in->buffer->size);
2279#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002280 return(nbchars);
2281}
2282
2283/**
2284 * xmlParserInputBufferRead:
2285 * @in: a buffered parser input
2286 * @len: indicative value of the amount of chars to read
2287 *
2288 * Refresh the content of the input buffer, the old data are considered
2289 * consumed
2290 * This routine handle the I18N transcoding to internal UTF-8
2291 *
2292 * Returns the number of chars read and stored in the buffer, or -1
2293 * in case of error.
2294 */
2295int
2296xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2297 /* xmlBufferEmpty(in->buffer); */
2298 if (in->readcallback != NULL)
2299 return(xmlParserInputBufferGrow(in, len));
2300 else
2301 return(-1);
2302}
2303
2304/**
2305 * xmlOutputBufferWrite:
2306 * @out: a buffered parser output
2307 * @len: the size in bytes of the array.
2308 * @buf: an char array
2309 *
2310 * Write the content of the array in the output I/O buffer
2311 * This routine handle the I18N transcoding from internal UTF-8
2312 * The buffer is lossless, i.e. will store in case of partial
2313 * or delayed writes.
2314 *
2315 * Returns the number of chars immediately written, or -1
2316 * in case of error.
2317 */
2318int
2319xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2320 int nbchars = 0; /* number of chars to output to I/O */
2321 int ret; /* return from function call */
2322 int written = 0; /* number of char written to I/O so far */
2323 int chunk; /* number of byte curreent processed from buf */
2324
2325 if (len < 0) return(0);
2326
2327 do {
2328 chunk = len;
2329 if (chunk > 4 * MINLEN)
2330 chunk = 4 * MINLEN;
2331
2332 /*
2333 * first handle encoding stuff.
2334 */
2335 if (out->encoder != NULL) {
2336 /*
2337 * Store the data in the incoming raw buffer
2338 */
2339 if (out->conv == NULL) {
2340 out->conv = xmlBufferCreate();
2341 }
2342 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2343
2344 if ((out->buffer->use < MINLEN) && (chunk == len))
2345 goto done;
2346
2347 /*
2348 * convert as much as possible to the parser reading buffer.
2349 */
2350 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2351 if (ret < 0) {
2352 xmlGenericError(xmlGenericErrorContext,
2353 "xmlOutputBufferWrite: encoder error\n");
2354 return(-1);
2355 }
2356 nbchars = out->conv->use;
2357 } else {
2358 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2359 nbchars = out->buffer->use;
2360 }
2361 buf += chunk;
2362 len -= chunk;
2363
2364 if ((nbchars < MINLEN) && (len <= 0))
2365 goto done;
2366
2367 if (out->writecallback) {
2368 /*
2369 * second write the stuff to the I/O channel
2370 */
2371 if (out->encoder != NULL) {
2372 ret = out->writecallback(out->context,
2373 (const char *)out->conv->content, nbchars);
2374 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002375 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002376 } else {
2377 ret = out->writecallback(out->context,
2378 (const char *)out->buffer->content, nbchars);
2379 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002380 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002381 }
2382 if (ret < 0) {
2383 xmlGenericError(xmlGenericErrorContext,
2384 "I/O: error %d writing %d bytes\n", ret, nbchars);
2385 return(ret);
2386 }
2387 out->written += ret;
2388 }
2389 written += nbchars;
2390 } while (len > 0);
2391
2392done:
2393#ifdef DEBUG_INPUT
2394 xmlGenericError(xmlGenericErrorContext,
2395 "I/O: wrote %d chars\n", written);
2396#endif
2397 return(written);
2398}
2399
2400/**
2401 * xmlOutputBufferWriteString:
2402 * @out: a buffered parser output
2403 * @str: a zero terminated C string
2404 *
2405 * Write the content of the string in the output I/O buffer
2406 * This routine handle the I18N transcoding from internal UTF-8
2407 * The buffer is lossless, i.e. will store in case of partial
2408 * or delayed writes.
2409 *
2410 * Returns the number of chars immediately written, or -1
2411 * in case of error.
2412 */
2413int
2414xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2415 int len;
2416
2417 if (str == NULL)
2418 return(-1);
2419 len = strlen(str);
2420
2421 if (len > 0)
2422 return(xmlOutputBufferWrite(out, len, str));
2423 return(len);
2424}
2425
2426/**
2427 * xmlOutputBufferFlush:
2428 * @out: a buffered output
2429 *
2430 * flushes the output I/O channel
2431 *
2432 * Returns the number of byte written or -1 in case of error.
2433 */
2434int
2435xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2436 int nbchars = 0, ret = 0;
2437
2438 /*
2439 * first handle encoding stuff.
2440 */
2441 if ((out->conv != NULL) && (out->encoder != NULL)) {
2442 /*
2443 * convert as much as possible to the parser reading buffer.
2444 */
2445 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2446 if (nbchars < 0) {
2447 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002448 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002449 return(-1);
2450 }
2451 }
2452
2453 /*
2454 * second flush the stuff to the I/O channel
2455 */
2456 if ((out->conv != NULL) && (out->encoder != NULL) &&
2457 (out->writecallback != NULL)) {
2458 ret = out->writecallback(out->context,
2459 (const char *)out->conv->content, out->conv->use);
2460 if (ret >= 0)
2461 xmlBufferShrink(out->conv, ret);
2462 } else if (out->writecallback != NULL) {
2463 ret = out->writecallback(out->context,
2464 (const char *)out->buffer->content, out->buffer->use);
2465 if (ret >= 0)
2466 xmlBufferShrink(out->buffer, ret);
2467 }
2468 if (ret < 0) {
2469 xmlGenericError(xmlGenericErrorContext,
2470 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2471 return(ret);
2472 }
2473 out->written += ret;
2474
2475#ifdef DEBUG_INPUT
2476 xmlGenericError(xmlGenericErrorContext,
2477 "I/O: flushed %d chars\n", ret);
2478#endif
2479 return(ret);
2480}
2481
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002482/**
Owen Taylor3473f882001-02-23 17:55:21 +00002483 * xmlParserGetDirectory:
2484 * @filename: the path to a file
2485 *
2486 * lookup the directory for that file
2487 *
2488 * Returns a new allocated string containing the directory, or NULL.
2489 */
2490char *
2491xmlParserGetDirectory(const char *filename) {
2492 char *ret = NULL;
2493 char dir[1024];
2494 char *cur;
2495 char sep = '/';
2496
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002497#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2498 return NULL;
2499#endif
2500
Owen Taylor3473f882001-02-23 17:55:21 +00002501 if (xmlInputCallbackInitialized == 0)
2502 xmlRegisterDefaultInputCallbacks();
2503
2504 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002505#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002506 sep = '\\';
2507#endif
2508
2509 strncpy(dir, filename, 1023);
2510 dir[1023] = 0;
2511 cur = &dir[strlen(dir)];
2512 while (cur > dir) {
2513 if (*cur == sep) break;
2514 cur --;
2515 }
2516 if (*cur == sep) {
2517 if (cur == dir) dir[1] = 0;
2518 else *cur = 0;
2519 ret = xmlMemStrdup(dir);
2520 } else {
2521 if (getcwd(dir, 1024) != NULL) {
2522 dir[1023] = 0;
2523 ret = xmlMemStrdup(dir);
2524 }
2525 }
2526 return(ret);
2527}
2528
2529/****************************************************************
2530 * *
2531 * External entities loading *
2532 * *
2533 ****************************************************************/
2534
Daniel Veillard561b7f82002-03-20 21:55:57 +00002535#ifdef LIBXML_CATALOG_ENABLED
2536static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002537#ifdef HAVE_STAT
2538 int ret;
2539 struct stat info;
2540 const char *path;
2541
2542 if (URL == NULL)
2543 return(0);
2544
Daniel Veillardf4862f02002-09-10 11:13:43 +00002545 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
2546#if defined (_WIN32) && !defined(__CYGWIN__)
2547 path = &URL[17];
2548#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002549 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002550#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002551 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002552#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002553 path = &URL[8];
2554#else
2555 path = &URL[7];
2556#endif
2557 } else
2558 path = URL;
2559 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002560 if (ret == 0)
2561 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002562#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002563 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002564}
Daniel Veillard561b7f82002-03-20 21:55:57 +00002565#endif
Daniel Veillard6990bf32001-08-23 21:17:48 +00002566
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002567/**
Owen Taylor3473f882001-02-23 17:55:21 +00002568 * xmlDefaultExternalEntityLoader:
2569 * @URL: the URL for the entity to load
2570 * @ID: the System ID for the entity to load
2571 * @ctxt: the context in which the entity is called or NULL
2572 *
2573 * By default we don't load external entitites, yet.
2574 *
2575 * Returns a new allocated xmlParserInputPtr, or NULL.
2576 */
2577static
2578xmlParserInputPtr
2579xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2580 xmlParserCtxtPtr ctxt) {
2581 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002582 xmlChar *resource = NULL;
2583#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002584 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002585#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002586
2587#ifdef DEBUG_EXTERNAL_ENTITIES
2588 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002589 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002590#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002591#ifdef LIBXML_CATALOG_ENABLED
2592 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002593 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002594 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002595 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002596 pref = xmlCatalogGetDefaults();
2597
Daniel Veillard561b7f82002-03-20 21:55:57 +00002598 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002599 /*
2600 * Do a local lookup
2601 */
2602 if ((ctxt->catalogs != NULL) &&
2603 ((pref == XML_CATA_ALLOW_ALL) ||
2604 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2605 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2606 (const xmlChar *)ID,
2607 (const xmlChar *)URL);
2608 }
2609 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002610 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002611 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002612 if ((resource == NULL) &&
2613 ((pref == XML_CATA_ALLOW_ALL) ||
2614 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002615 resource = xmlCatalogResolve((const xmlChar *)ID,
2616 (const xmlChar *)URL);
2617 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002618 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002619 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002620
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002621 /*
2622 * TODO: do an URI lookup on the reference
2623 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002624 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002625 xmlChar *tmp = NULL;
2626
2627 if ((ctxt->catalogs != NULL) &&
2628 ((pref == XML_CATA_ALLOW_ALL) ||
2629 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2630 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2631 }
2632 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002633 ((pref == XML_CATA_ALLOW_ALL) ||
2634 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002635 tmp = xmlCatalogResolveURI(resource);
2636 }
2637
2638 if (tmp != NULL) {
2639 xmlFree(resource);
2640 resource = tmp;
2641 }
2642 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002643 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002644#endif
2645
2646 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002647 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002648
2649 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002650 if (ID == NULL)
2651 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002652 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2653 (ctxt->sax->error != NULL))
2654 ctxt->sax->error(ctxt,
2655 "failed to load external entity \"%s\"\n", ID);
2656 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002657 ctxt->sax->warning(ctxt,
2658 "failed to load external entity \"%s\"\n", ID);
2659 return(NULL);
2660 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002661 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002662 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002663 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2664 (ctxt->sax->error != NULL))
2665 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002666 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002667 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002668 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002669 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002670 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002671 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002672 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002673 return(ret);
2674}
2675
2676static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2677 xmlDefaultExternalEntityLoader;
2678
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002679/**
Owen Taylor3473f882001-02-23 17:55:21 +00002680 * xmlSetExternalEntityLoader:
2681 * @f: the new entity resolver function
2682 *
2683 * Changes the defaultexternal entity resolver function for the application
2684 */
2685void
2686xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2687 xmlCurrentExternalEntityLoader = f;
2688}
2689
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002690/**
Owen Taylor3473f882001-02-23 17:55:21 +00002691 * xmlGetExternalEntityLoader:
2692 *
2693 * Get the default external entity resolver function for the application
2694 *
2695 * Returns the xmlExternalEntityLoader function pointer
2696 */
2697xmlExternalEntityLoader
2698xmlGetExternalEntityLoader(void) {
2699 return(xmlCurrentExternalEntityLoader);
2700}
2701
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002702/**
Owen Taylor3473f882001-02-23 17:55:21 +00002703 * xmlLoadExternalEntity:
2704 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002705 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002706 * @ctxt: the context in which the entity is called or NULL
2707 *
2708 * Load an external entity, note that the use of this function for
2709 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002710 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002711 *
2712 * Returns the xmlParserInputPtr or NULL
2713 */
2714xmlParserInputPtr
2715xmlLoadExternalEntity(const char *URL, const char *ID,
2716 xmlParserCtxtPtr ctxt) {
2717 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2718}
2719
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002720/************************************************************************
2721 * *
2722 * Disabling Network access *
2723 * *
2724 ************************************************************************/
2725
2726#ifdef LIBXML_CATALOG_ENABLED
2727static int
2728xmlNoNetExists(const char *URL)
2729{
2730#ifdef HAVE_STAT
2731 int ret;
2732 struct stat info;
2733 const char *path;
2734
2735 if (URL == NULL)
2736 return (0);
2737
Daniel Veillardf4862f02002-09-10 11:13:43 +00002738 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
2739#if defined (_WIN32) && !defined(__CYGWIN__)
2740 path = &URL[17];
2741#else
2742 path = &URL[16];
2743#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002744 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002745#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002746 path = &URL[8];
2747#else
2748 path = &URL[7];
2749#endif
2750 } else
2751 path = URL;
2752 ret = stat(path, &info);
2753 if (ret == 0)
2754 return (1);
2755#endif
2756 return (0);
2757}
2758#endif
2759
2760/**
2761 * xmlNoNetExternalEntityLoader:
2762 * @URL: the URL for the entity to load
2763 * @ID: the System ID for the entity to load
2764 * @ctxt: the context in which the entity is called or NULL
2765 *
2766 * A specific entity loader disabling network accesses, though still
2767 * allowing local catalog accesses for resolution.
2768 *
2769 * Returns a new allocated xmlParserInputPtr, or NULL.
2770 */
2771xmlParserInputPtr
2772xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2773 xmlParserCtxtPtr ctxt) {
2774 xmlParserInputPtr input = NULL;
2775 xmlChar *resource = NULL;
2776
2777#ifdef LIBXML_CATALOG_ENABLED
2778 xmlCatalogAllow pref;
2779
2780 /*
2781 * If the resource doesn't exists as a file,
2782 * try to load it from the resource pointed in the catalogs
2783 */
2784 pref = xmlCatalogGetDefaults();
2785
2786 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2787 /*
2788 * Do a local lookup
2789 */
2790 if ((ctxt->catalogs != NULL) &&
2791 ((pref == XML_CATA_ALLOW_ALL) ||
2792 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2793 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2794 (const xmlChar *)ID,
2795 (const xmlChar *)URL);
2796 }
2797 /*
2798 * Try a global lookup
2799 */
2800 if ((resource == NULL) &&
2801 ((pref == XML_CATA_ALLOW_ALL) ||
2802 (pref == XML_CATA_ALLOW_GLOBAL))) {
2803 resource = xmlCatalogResolve((const xmlChar *)ID,
2804 (const xmlChar *)URL);
2805 }
2806 if ((resource == NULL) && (URL != NULL))
2807 resource = xmlStrdup((const xmlChar *) URL);
2808
2809 /*
2810 * TODO: do an URI lookup on the reference
2811 */
2812 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2813 xmlChar *tmp = NULL;
2814
2815 if ((ctxt->catalogs != NULL) &&
2816 ((pref == XML_CATA_ALLOW_ALL) ||
2817 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2818 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2819 }
2820 if ((tmp == NULL) &&
2821 ((pref == XML_CATA_ALLOW_ALL) ||
2822 (pref == XML_CATA_ALLOW_GLOBAL))) {
2823 tmp = xmlCatalogResolveURI(resource);
2824 }
2825
2826 if (tmp != NULL) {
2827 xmlFree(resource);
2828 resource = tmp;
2829 }
2830 }
2831 }
2832#endif
2833 if (resource == NULL)
2834 resource = (xmlChar *) URL;
2835
2836 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002837 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2838 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002839 xmlGenericError(xmlGenericErrorContext,
2840 "Attempt to load network entity %s \n", resource);
2841
2842 if (resource != (xmlChar *) URL)
2843 xmlFree(resource);
2844 return(NULL);
2845 }
2846 }
2847 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2848 if (resource != (xmlChar *) URL)
2849 xmlFree(resource);
2850 return(input);
2851}
2852