blob: a7269c7412e4d725470b1b9f38fd28bc2da1f400 [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 Veillardc5d64342001-06-24 12:13:24 +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
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <string.h>
14#include <errno.h>
15
16#ifdef HAVE_SYS_TYPES_H
17#include <sys/types.h>
18#endif
19#ifdef HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#ifdef HAVE_FCNTL_H
23#include <fcntl.h>
24#endif
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#ifdef HAVE_STDLIB_H
29#include <stdlib.h>
30#endif
31#ifdef HAVE_ZLIB_H
32#include <zlib.h>
33#endif
34
35/* Figure a portable way to know if a file is a directory. */
36#ifndef HAVE_STAT
37# ifdef HAVE__STAT
38# define stat(x,y) _stat(x,y)
39# define HAVE_STAT
40# endif
41#endif
42#ifdef HAVE_STAT
43# ifndef S_ISDIR
44# ifdef _S_ISDIR
45# define S_ISDIR(x) _S_ISDIR(x)
46# else
47# ifdef S_IFDIR
48# ifndef S_IFMT
49# ifdef _S_IFMT
50# define S_IFMT _S_IFMT
51# endif
52# endif
53# ifdef S_IFMT
54# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
55# endif
56# endif
57# endif
58# endif
59#endif
60
61#include <libxml/xmlmemory.h>
62#include <libxml/parser.h>
63#include <libxml/parserInternals.h>
64#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000065#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000066#include <libxml/nanohttp.h>
67#include <libxml/nanoftp.h>
68#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000069#ifdef LIBXML_CATALOG_ENABLED
70#include <libxml/catalog.h>
71#endif
Owen Taylor3473f882001-02-23 17:55:21 +000072
73#ifdef VMS
74#define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
75#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
76#endif
77
Daniel Veillard1fd36d22001-07-04 22:54:28 +000078/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000079/* #define DEBUG_INPUT */
80
81#ifdef DEBUG_INPUT
82#define MINLEN 40
83#else
84#define MINLEN 4000
85#endif
86
87/*
88 * Input I/O callback sets
89 */
90typedef struct _xmlInputCallback {
91 xmlInputMatchCallback matchcallback;
92 xmlInputOpenCallback opencallback;
93 xmlInputReadCallback readcallback;
94 xmlInputCloseCallback closecallback;
95} xmlInputCallback;
96
97#define MAX_INPUT_CALLBACK 15
98
Daniel Veillard22090732001-07-16 00:06:07 +000099static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
100static int xmlInputCallbackNr = 0;
101static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000102
103/*
104 * Output I/O callback sets
105 */
106typedef struct _xmlOutputCallback {
107 xmlOutputMatchCallback matchcallback;
108 xmlOutputOpenCallback opencallback;
109 xmlOutputWriteCallback writecallback;
110 xmlOutputCloseCallback closecallback;
111} xmlOutputCallback;
112
113#define MAX_OUTPUT_CALLBACK 15
114
Daniel Veillard22090732001-07-16 00:06:07 +0000115static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
116static int xmlOutputCallbackNr = 0;
117static int xmlOutputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000118
119/************************************************************************
120 * *
121 * Standard I/O for file accesses *
122 * *
123 ************************************************************************/
124
125/**
126 * xmlCheckFilename
127 * @path: the path to check
128 *
129 * function checks to see if @path is a valid source
130 * (file, socket...) for XML.
131 *
132 * if stat is not available on the target machine,
133 * returns 1. if stat fails, returns 0 (if calling
134 * stat on the filename fails, it can't be right).
135 * if stat succeeds and the file is a directory,
136 * sets errno to EISDIR and returns 0. otherwise
137 * returns 1.
138 */
139
140static int
141xmlCheckFilename (const char *path)
142{
143#ifdef HAVE_STAT
144#ifdef S_ISDIR
145 struct stat stat_buffer;
146
147 if (stat(path, &stat_buffer) == -1)
148 return 0;
149
150 if (S_ISDIR(stat_buffer.st_mode)) {
151 errno = EISDIR;
152 return 0;
153 }
154
155#endif
156#endif
157 return 1;
158}
159
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000160static int
Owen Taylor3473f882001-02-23 17:55:21 +0000161xmlNop(void) {
162 return(0);
163}
164
165/**
Owen Taylor3473f882001-02-23 17:55:21 +0000166 * xmlFdRead:
167 * @context: the I/O context
168 * @buffer: where to drop data
169 * @len: number of bytes to read
170 *
171 * Read @len bytes to @buffer from the I/O channel.
172 *
173 * Returns the number of bytes written
174 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000175static int
Owen Taylor3473f882001-02-23 17:55:21 +0000176xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000177 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000178}
179
180/**
181 * xmlFdWrite:
182 * @context: the I/O context
183 * @buffer: where to get data
184 * @len: number of bytes to write
185 *
186 * Write @len bytes from @buffer to the I/O channel.
187 *
188 * Returns the number of bytes written
189 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000190static int
Owen Taylor3473f882001-02-23 17:55:21 +0000191xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000192 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000193}
194
195/**
196 * xmlFdClose:
197 * @context: the I/O context
198 *
199 * Close an I/O channel
200 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000201static void
Owen Taylor3473f882001-02-23 17:55:21 +0000202xmlFdClose (void * context) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000203 close((int) (long) context);
Owen Taylor3473f882001-02-23 17:55:21 +0000204}
205
206/**
207 * xmlFileMatch:
208 * @filename: the URI for matching
209 *
210 * input from FILE *
211 *
212 * Returns 1 if matches, 0 otherwise
213 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000214static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000215xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000216 return(1);
217}
218
219/**
220 * xmlFileOpen:
221 * @filename: the URI for matching
222 *
223 * input from FILE *, supports compressed input
224 * if @filename is " " then the standard input is used
225 *
226 * Returns an I/O context or NULL in case of error
227 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000228static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000229xmlFileOpen (const char *filename) {
230 const char *path = NULL;
231 FILE *fd;
232
233 if (!strcmp(filename, "-")) {
234 fd = stdin;
235 return((void *) fd);
236 }
237
238 if (!strncmp(filename, "file://localhost", 16))
239 path = &filename[16];
240 else if (!strncmp(filename, "file:///", 8))
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000241 path = &filename[7];
Owen Taylor3473f882001-02-23 17:55:21 +0000242 else
243 path = filename;
244
245 if (path == NULL)
246 return(NULL);
247 if (!xmlCheckFilename(path))
248 return(NULL);
249
250#ifdef WIN32
251 fd = fopen(path, "rb");
252#else
253 fd = fopen(path, "r");
254#endif /* WIN32 */
255 return((void *) fd);
256}
257
258/**
259 * xmlFileOpenW:
260 * @filename: the URI for matching
261 *
262 * output to from FILE *,
263 * if @filename is "-" then the standard output is used
264 *
265 * Returns an I/O context or NULL in case of error
266 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000267static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000268xmlFileOpenW (const char *filename) {
269 const char *path = NULL;
270 FILE *fd;
271
272 if (!strcmp(filename, "-")) {
273 fd = stdout;
274 return((void *) fd);
275 }
276
277 if (!strncmp(filename, "file://localhost", 16))
278 path = &filename[16];
279 else if (!strncmp(filename, "file:///", 8))
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000280 path = &filename[7];
Owen Taylor3473f882001-02-23 17:55:21 +0000281 else
282 path = filename;
283
284 if (path == NULL)
285 return(NULL);
286
287 fd = fopen(path, "w");
288 return((void *) fd);
289}
290
291/**
292 * xmlFileRead:
293 * @context: the I/O context
294 * @buffer: where to drop data
295 * @len: number of bytes to write
296 *
297 * Read @len bytes to @buffer from the I/O channel.
298 *
299 * Returns the number of bytes written
300 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000301static int
Owen Taylor3473f882001-02-23 17:55:21 +0000302xmlFileRead (void * context, char * buffer, int len) {
303 return(fread(&buffer[0], 1, len, (FILE *) context));
304}
305
306/**
307 * xmlFileWrite:
308 * @context: the I/O context
309 * @buffer: where to drop data
310 * @len: number of bytes to write
311 *
312 * Write @len bytes from @buffer to the I/O channel.
313 *
314 * Returns the number of bytes written
315 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000316static int
Owen Taylor3473f882001-02-23 17:55:21 +0000317xmlFileWrite (void * context, const char * buffer, int len) {
318 return(fwrite(&buffer[0], 1, len, (FILE *) context));
319}
320
321/**
322 * xmlFileClose:
323 * @context: the I/O context
324 *
325 * Close an I/O channel
326 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000327static void
Owen Taylor3473f882001-02-23 17:55:21 +0000328xmlFileClose (void * context) {
329 fclose((FILE *) context);
330}
331
332/**
333 * xmlFileFlush:
334 * @context: the I/O context
335 *
336 * Flush an I/O channel
337 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000338static void
Owen Taylor3473f882001-02-23 17:55:21 +0000339xmlFileFlush (void * context) {
340 fflush((FILE *) context);
341}
342
343#ifdef HAVE_ZLIB_H
344/************************************************************************
345 * *
346 * I/O for compressed file accesses *
347 * *
348 ************************************************************************/
349/**
350 * xmlGzfileMatch:
351 * @filename: the URI for matching
352 *
353 * input from compressed file test
354 *
355 * Returns 1 if matches, 0 otherwise
356 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000357static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000358xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000359 return(1);
360}
361
362/**
363 * xmlGzfileOpen:
364 * @filename: the URI for matching
365 *
366 * input from compressed file open
367 * if @filename is " " then the standard input is used
368 *
369 * Returns an I/O context or NULL in case of error
370 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000371static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000372xmlGzfileOpen (const char *filename) {
373 const char *path = NULL;
374 gzFile fd;
375
376 if (!strcmp(filename, "-")) {
377 fd = gzdopen(fileno(stdin), "rb");
378 return((void *) fd);
379 }
380
381 if (!strncmp(filename, "file://localhost", 16))
382 path = &filename[16];
383 else if (!strncmp(filename, "file:///", 8))
384 path = &filename[7];
385 else
386 path = filename;
387
388 if (path == NULL)
389 return(NULL);
390 if (!xmlCheckFilename(path))
391 return(NULL);
392
393 fd = gzopen(path, "rb");
394 return((void *) fd);
395}
396
397/**
398 * xmlGzfileOpenW:
399 * @filename: the URI for matching
400 * @compression: the compression factor (0 - 9 included)
401 *
402 * input from compressed file open
403 * if @filename is " " then the standard input is used
404 *
405 * Returns an I/O context or NULL in case of error
406 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000407static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000408xmlGzfileOpenW (const char *filename, int compression) {
409 const char *path = NULL;
410 char mode[15];
411 gzFile fd;
412
413 sprintf(mode, "wb%d", compression);
414 if (!strcmp(filename, "-")) {
415 fd = gzdopen(1, mode);
416 return((void *) fd);
417 }
418
419 if (!strncmp(filename, "file://localhost", 16))
420 path = &filename[16];
421 else if (!strncmp(filename, "file:///", 8))
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000422 path = &filename[7];
Owen Taylor3473f882001-02-23 17:55:21 +0000423 else
424 path = filename;
425
426 if (path == NULL)
427 return(NULL);
428
429 fd = gzopen(path, mode);
430 return((void *) fd);
431}
432
433/**
434 * xmlGzfileRead:
435 * @context: the I/O context
436 * @buffer: where to drop data
437 * @len: number of bytes to write
438 *
439 * Read @len bytes to @buffer from the compressed I/O channel.
440 *
441 * Returns the number of bytes written
442 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000443static int
Owen Taylor3473f882001-02-23 17:55:21 +0000444xmlGzfileRead (void * context, char * buffer, int len) {
445 return(gzread((gzFile) context, &buffer[0], len));
446}
447
448/**
449 * xmlGzfileWrite:
450 * @context: the I/O context
451 * @buffer: where to drop data
452 * @len: number of bytes to write
453 *
454 * Write @len bytes from @buffer to the compressed I/O channel.
455 *
456 * Returns the number of bytes written
457 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000458static int
Owen Taylor3473f882001-02-23 17:55:21 +0000459xmlGzfileWrite (void * context, const char * buffer, int len) {
460 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
461}
462
463/**
464 * xmlGzfileClose:
465 * @context: the I/O context
466 *
467 * Close a compressed I/O channel
468 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000469static void
Owen Taylor3473f882001-02-23 17:55:21 +0000470xmlGzfileClose (void * context) {
471 gzclose((gzFile) context);
472}
473#endif /* HAVE_ZLIB_H */
474
475#ifdef LIBXML_HTTP_ENABLED
476/************************************************************************
477 * *
478 * I/O for HTTP file accesses *
479 * *
480 ************************************************************************/
481/**
482 * xmlIOHTTPMatch:
483 * @filename: the URI for matching
484 *
485 * check if the URI matches an HTTP one
486 *
487 * Returns 1 if matches, 0 otherwise
488 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000489static int
Owen Taylor3473f882001-02-23 17:55:21 +0000490xmlIOHTTPMatch (const char *filename) {
491 if (!strncmp(filename, "http://", 7))
492 return(1);
493 return(0);
494}
495
496/**
497 * xmlIOHTTPOpen:
498 * @filename: the URI for matching
499 *
500 * open an HTTP I/O channel
501 *
502 * Returns an I/O context or NULL in case of error
503 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000504static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000505xmlIOHTTPOpen (const char *filename) {
506 return(xmlNanoHTTPOpen(filename, NULL));
507}
508
509/**
510 * xmlIOHTTPRead:
511 * @context: the I/O context
512 * @buffer: where to drop data
513 * @len: number of bytes to write
514 *
515 * Read @len bytes to @buffer from the I/O channel.
516 *
517 * Returns the number of bytes written
518 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000519static int
Owen Taylor3473f882001-02-23 17:55:21 +0000520xmlIOHTTPRead(void * context, char * buffer, int len) {
521 return(xmlNanoHTTPRead(context, &buffer[0], len));
522}
523
524/**
525 * xmlIOHTTPClose:
526 * @context: the I/O context
527 *
528 * Close an HTTP I/O channel
529 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000530static void
Owen Taylor3473f882001-02-23 17:55:21 +0000531xmlIOHTTPClose (void * context) {
532 xmlNanoHTTPClose(context);
533}
534#endif /* LIBXML_HTTP_ENABLED */
535
536#ifdef LIBXML_FTP_ENABLED
537/************************************************************************
538 * *
539 * I/O for FTP file accesses *
540 * *
541 ************************************************************************/
542/**
543 * xmlIOFTPMatch:
544 * @filename: the URI for matching
545 *
546 * check if the URI matches an FTP one
547 *
548 * Returns 1 if matches, 0 otherwise
549 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000550static int
Owen Taylor3473f882001-02-23 17:55:21 +0000551xmlIOFTPMatch (const char *filename) {
552 if (!strncmp(filename, "ftp://", 6))
553 return(1);
554 return(0);
555}
556
557/**
558 * xmlIOFTPOpen:
559 * @filename: the URI for matching
560 *
561 * open an FTP I/O channel
562 *
563 * Returns an I/O context or NULL in case of error
564 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000565static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000566xmlIOFTPOpen (const char *filename) {
567 return(xmlNanoFTPOpen(filename));
568}
569
570/**
571 * xmlIOFTPRead:
572 * @context: the I/O context
573 * @buffer: where to drop data
574 * @len: number of bytes to write
575 *
576 * Read @len bytes to @buffer from the I/O channel.
577 *
578 * Returns the number of bytes written
579 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000580static int
Owen Taylor3473f882001-02-23 17:55:21 +0000581xmlIOFTPRead(void * context, char * buffer, int len) {
582 return(xmlNanoFTPRead(context, &buffer[0], len));
583}
584
585/**
586 * xmlIOFTPClose:
587 * @context: the I/O context
588 *
589 * Close an FTP I/O channel
590 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000591static void
Owen Taylor3473f882001-02-23 17:55:21 +0000592xmlIOFTPClose (void * context) {
593 xmlNanoFTPClose(context);
594}
595#endif /* LIBXML_FTP_ENABLED */
596
597
598/**
599 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000600 * @matchFunc: the xmlInputMatchCallback
601 * @openFunc: the xmlInputOpenCallback
602 * @readFunc: the xmlInputReadCallback
603 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +0000604 *
605 * Register a new set of I/O callback for handling parser input.
606 *
607 * Returns the registered handler number or -1 in case of error
608 */
609int
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000610xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
611 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
612 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +0000613 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
614 return(-1);
615 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000616 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
617 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
618 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
619 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000620 return(xmlInputCallbackNr++);
621}
622
623/**
624 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000625 * @matchFunc: the xmlOutputMatchCallback
626 * @openFunc: the xmlOutputOpenCallback
627 * @writeFunc: the xmlOutputWriteCallback
628 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +0000629 *
630 * Register a new set of I/O callback for handling output.
631 *
632 * Returns the registered handler number or -1 in case of error
633 */
634int
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000635xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
636 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
637 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +0000638 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
639 return(-1);
640 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000641 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
642 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
643 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
644 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000645 return(xmlOutputCallbackNr++);
646}
647
648/**
649 * xmlRegisterDefaultInputCallbacks:
650 *
651 * Registers the default compiled-in I/O handlers.
652 */
653void
654#ifdef VMS
655xmlRegisterDefInputCallbacks
656#else
657xmlRegisterDefaultInputCallbacks
658#endif
659(void) {
660 if (xmlInputCallbackInitialized)
661 return;
662
663 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
664 xmlFileRead, xmlFileClose);
665#ifdef HAVE_ZLIB_H
666 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
667 xmlGzfileRead, xmlGzfileClose);
668#endif /* HAVE_ZLIB_H */
669
670#ifdef LIBXML_HTTP_ENABLED
671 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
672 xmlIOHTTPRead, xmlIOHTTPClose);
673#endif /* LIBXML_HTTP_ENABLED */
674
675#ifdef LIBXML_FTP_ENABLED
676 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
677 xmlIOFTPRead, xmlIOFTPClose);
678#endif /* LIBXML_FTP_ENABLED */
679 xmlInputCallbackInitialized = 1;
680}
681
682/**
683 * xmlRegisterDefaultOutputCallbacks:
684 *
685 * Registers the default compiled-in I/O handlers.
686 */
687void
688#ifdef VMS
689xmlRegisterDefOutputCallbacks
690#else
691xmlRegisterDefaultOutputCallbacks
692#endif
693(void) {
694 if (xmlOutputCallbackInitialized)
695 return;
696
697 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
698 xmlFileWrite, xmlFileClose);
699/*********************************
700 No way a-priori to distinguish between gzipped files from
701 uncompressed ones except opening if existing then closing
702 and saving with same compression ratio ... a pain.
703
704#ifdef HAVE_ZLIB_H
705 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
706 xmlGzfileWrite, xmlGzfileClose);
707#endif
708 No HTTP PUT support yet, patches welcome
709
710#ifdef LIBXML_HTTP_ENABLED
711 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
712 xmlIOHTTPWrite, xmlIOHTTPClose);
713#endif
714
715 Nor FTP PUT ....
716#ifdef LIBXML_FTP_ENABLED
717 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
718 xmlIOFTPWrite, xmlIOFTPClose);
719#endif
720 **********************************/
721 xmlOutputCallbackInitialized = 1;
722}
723
724/**
725 * xmlAllocParserInputBuffer:
726 * @enc: the charset encoding if known
727 *
728 * Create a buffered parser input for progressive parsing
729 *
730 * Returns the new parser input or NULL
731 */
732xmlParserInputBufferPtr
733xmlAllocParserInputBuffer(xmlCharEncoding enc) {
734 xmlParserInputBufferPtr ret;
735
736 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
737 if (ret == NULL) {
738 xmlGenericError(xmlGenericErrorContext,
739 "xmlAllocParserInputBuffer : out of memory!\n");
740 return(NULL);
741 }
742 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
743 ret->buffer = xmlBufferCreate();
744 if (ret->buffer == NULL) {
745 xmlFree(ret);
746 return(NULL);
747 }
748 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
749 ret->encoder = xmlGetCharEncodingHandler(enc);
750 if (ret->encoder != NULL)
751 ret->raw = xmlBufferCreate();
752 else
753 ret->raw = NULL;
754 ret->readcallback = NULL;
755 ret->closecallback = NULL;
756 ret->context = NULL;
757
758 return(ret);
759}
760
761/**
762 * xmlAllocOutputBuffer:
763 * @encoder: the encoding converter or NULL
764 *
765 * Create a buffered parser output
766 *
767 * Returns the new parser output or NULL
768 */
769xmlOutputBufferPtr
770xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
771 xmlOutputBufferPtr ret;
772
773 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
774 if (ret == NULL) {
775 xmlGenericError(xmlGenericErrorContext,
776 "xmlAllocOutputBuffer : out of memory!\n");
777 return(NULL);
778 }
779 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
780 ret->buffer = xmlBufferCreate();
781 if (ret->buffer == NULL) {
782 xmlFree(ret);
783 return(NULL);
784 }
785 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
786 ret->encoder = encoder;
787 if (encoder != NULL) {
788 ret->conv = xmlBufferCreateSize(4000);
789 /*
790 * This call is designed to initiate the encoder state
791 */
792 xmlCharEncOutFunc(encoder, ret->conv, NULL);
793 } else
794 ret->conv = NULL;
795 ret->writecallback = NULL;
796 ret->closecallback = NULL;
797 ret->context = NULL;
798 ret->written = 0;
799
800 return(ret);
801}
802
803/**
804 * xmlFreeParserInputBuffer:
805 * @in: a buffered parser input
806 *
807 * Free up the memory used by a buffered parser input
808 */
809void
810xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
811 if (in->raw) {
812 xmlBufferFree(in->raw);
813 in->raw = NULL;
814 }
815 if (in->encoder != NULL) {
816 xmlCharEncCloseFunc(in->encoder);
817 }
818 if (in->closecallback != NULL) {
819 in->closecallback(in->context);
820 }
821 if (in->buffer != NULL) {
822 xmlBufferFree(in->buffer);
823 in->buffer = NULL;
824 }
825
Owen Taylor3473f882001-02-23 17:55:21 +0000826 xmlFree(in);
827}
828
829/**
830 * xmlOutputBufferClose:
831 * @out: a buffered output
832 *
833 * flushes and close the output I/O channel
834 * and free up all the associated resources
835 *
836 * Returns the number of byte written or -1 in case of error.
837 */
838int
839xmlOutputBufferClose(xmlOutputBufferPtr out) {
840 int written;
841
842 if (out == NULL)
843 return(-1);
844 if (out->writecallback != NULL)
845 xmlOutputBufferFlush(out);
846 if (out->closecallback != NULL) {
847 out->closecallback(out->context);
848 }
849 written = out->written;
850 if (out->conv) {
851 xmlBufferFree(out->conv);
852 out->conv = NULL;
853 }
854 if (out->encoder != NULL) {
855 xmlCharEncCloseFunc(out->encoder);
856 }
857 if (out->buffer != NULL) {
858 xmlBufferFree(out->buffer);
859 out->buffer = NULL;
860 }
861
Owen Taylor3473f882001-02-23 17:55:21 +0000862 xmlFree(out);
863 return(written);
864}
865
866/**
867 * xmlParserInputBufferCreateFilename:
868 * @URI: a C string containing the URI or filename
869 * @enc: the charset encoding if known
870 *
871 * Create a buffered parser input for the progressive parsing of a file
872 * If filename is "-' then we use stdin as the input.
873 * Automatic support for ZLIB/Compress compressed document is provided
874 * by default if found at compile-time.
875 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
876 *
877 * Returns the new parser input or NULL
878 */
879xmlParserInputBufferPtr
880#ifdef VMS
881xmlParserInputBufferCreateFname
882#else
883xmlParserInputBufferCreateFilename
884#endif
885(const char *URI, xmlCharEncoding enc) {
886 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +0000887 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000888 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +0000889 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +0000890
891 if (xmlInputCallbackInitialized == 0)
892 xmlRegisterDefaultInputCallbacks();
893
894 if (URI == NULL) return(NULL);
895
896 /*
897 * Try to find one of the input accept method accepting taht scheme
898 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +0000899 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +0000900 */
Daniel Veillard388236f2001-07-08 18:35:48 +0000901 unescaped = xmlURIUnescapeString(URI, 0, NULL);
902 if (unescaped != NULL) {
903 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
904 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
905 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
906 context = xmlInputCallbackTable[i].opencallback(unescaped);
907 if (context != NULL)
908 break;
909 }
910 }
911 xmlFree(unescaped);
912 }
913
914 /*
915 * If this failed try with a non-escaped URI this may be a strange
916 * filename
917 */
918 if (context == NULL) {
919 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
920 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
921 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
922 context = xmlInputCallbackTable[i].opencallback(URI);
923 if (context != NULL)
924 break;
925 }
Owen Taylor3473f882001-02-23 17:55:21 +0000926 }
927 }
928 if (context == NULL) {
929 return(NULL);
930 }
931
932 /*
933 * Allocate the Input buffer front-end.
934 */
935 ret = xmlAllocParserInputBuffer(enc);
936 if (ret != NULL) {
937 ret->context = context;
938 ret->readcallback = xmlInputCallbackTable[i].readcallback;
939 ret->closecallback = xmlInputCallbackTable[i].closecallback;
940 }
941 return(ret);
942}
943
944/**
945 * xmlOutputBufferCreateFilename:
946 * @URI: a C string containing the URI or filename
947 * @encoder: the encoding converter or NULL
948 * @compression: the compression ration (0 none, 9 max).
949 *
950 * Create a buffered output for the progressive saving of a file
951 * If filename is "-' then we use stdout as the output.
952 * Automatic support for ZLIB/Compress compressed document is provided
953 * by default if found at compile-time.
954 * TODO: currently if compression is set, the library only support
955 * writing to a local file.
956 *
957 * Returns the new output or NULL
958 */
959xmlOutputBufferPtr
960xmlOutputBufferCreateFilename(const char *URI,
961 xmlCharEncodingHandlerPtr encoder,
962 int compression) {
963 xmlOutputBufferPtr ret;
964 int i;
965 void *context = NULL;
966
967 if (xmlOutputCallbackInitialized == 0)
968 xmlRegisterDefaultOutputCallbacks();
969
970 if (URI == NULL) return(NULL);
971
972#ifdef HAVE_ZLIB_H
973 if ((compression > 0) && (compression <= 9)) {
974 context = xmlGzfileOpenW(URI, compression);
975 if (context != NULL) {
976 ret = xmlAllocOutputBuffer(encoder);
977 if (ret != NULL) {
978 ret->context = context;
979 ret->writecallback = xmlGzfileWrite;
980 ret->closecallback = xmlGzfileClose;
981 }
982 return(ret);
983 }
984 }
985#endif
986
987 /*
988 * Try to find one of the output accept method accepting taht scheme
989 * Go in reverse to give precedence to user defined handlers.
990 */
991 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
992 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
993 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
994 context = xmlOutputCallbackTable[i].opencallback(URI);
995 if (context != NULL)
996 break;
997 }
998 }
999 if (context == NULL) {
1000 return(NULL);
1001 }
1002
1003 /*
1004 * Allocate the Output buffer front-end.
1005 */
1006 ret = xmlAllocOutputBuffer(encoder);
1007 if (ret != NULL) {
1008 ret->context = context;
1009 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1010 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1011 }
1012 return(ret);
1013}
1014
1015/**
1016 * xmlParserInputBufferCreateFile:
1017 * @file: a FILE*
1018 * @enc: the charset encoding if known
1019 *
1020 * Create a buffered parser input for the progressive parsing of a FILE *
1021 * buffered C I/O
1022 *
1023 * Returns the new parser input or NULL
1024 */
1025xmlParserInputBufferPtr
1026xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1027 xmlParserInputBufferPtr ret;
1028
1029 if (xmlInputCallbackInitialized == 0)
1030 xmlRegisterDefaultInputCallbacks();
1031
1032 if (file == NULL) return(NULL);
1033
1034 ret = xmlAllocParserInputBuffer(enc);
1035 if (ret != NULL) {
1036 ret->context = file;
1037 ret->readcallback = xmlFileRead;
1038 ret->closecallback = xmlFileFlush;
1039 }
1040
1041 return(ret);
1042}
1043
1044/**
1045 * xmlOutputBufferCreateFile:
1046 * @file: a FILE*
1047 * @encoder: the encoding converter or NULL
1048 *
1049 * Create a buffered output for the progressive saving to a FILE *
1050 * buffered C I/O
1051 *
1052 * Returns the new parser output or NULL
1053 */
1054xmlOutputBufferPtr
1055xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1056 xmlOutputBufferPtr ret;
1057
1058 if (xmlOutputCallbackInitialized == 0)
1059 xmlRegisterDefaultOutputCallbacks();
1060
1061 if (file == NULL) return(NULL);
1062
1063 ret = xmlAllocOutputBuffer(encoder);
1064 if (ret != NULL) {
1065 ret->context = file;
1066 ret->writecallback = xmlFileWrite;
1067 ret->closecallback = xmlFileFlush;
1068 }
1069
1070 return(ret);
1071}
1072
1073/**
1074 * xmlParserInputBufferCreateFd:
1075 * @fd: a file descriptor number
1076 * @enc: the charset encoding if known
1077 *
1078 * Create a buffered parser input for the progressive parsing for the input
1079 * from a file descriptor
1080 *
1081 * Returns the new parser input or NULL
1082 */
1083xmlParserInputBufferPtr
1084xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1085 xmlParserInputBufferPtr ret;
1086
1087 if (fd < 0) return(NULL);
1088
1089 ret = xmlAllocParserInputBuffer(enc);
1090 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001091 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001092 ret->readcallback = xmlFdRead;
1093 ret->closecallback = xmlFdClose;
1094 }
1095
1096 return(ret);
1097}
1098
1099/**
1100 * xmlParserInputBufferCreateMem:
1101 * @mem: the memory input
1102 * @size: the length of the memory block
1103 * @enc: the charset encoding if known
1104 *
1105 * Create a buffered parser input for the progressive parsing for the input
1106 * from a memory area.
1107 *
1108 * Returns the new parser input or NULL
1109 */
1110xmlParserInputBufferPtr
1111xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1112 xmlParserInputBufferPtr ret;
1113
1114 if (size <= 0) return(NULL);
1115 if (mem == NULL) return(NULL);
1116
1117 ret = xmlAllocParserInputBuffer(enc);
1118 if (ret != NULL) {
1119 ret->context = (void *) mem;
1120 ret->readcallback = (xmlInputReadCallback) xmlNop;
1121 ret->closecallback = NULL;
1122 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1123 }
1124
1125 return(ret);
1126}
1127
1128/**
1129 * xmlOutputBufferCreateFd:
1130 * @fd: a file descriptor number
1131 * @encoder: the encoding converter or NULL
1132 *
1133 * Create a buffered output for the progressive saving
1134 * to a file descriptor
1135 *
1136 * Returns the new parser output or NULL
1137 */
1138xmlOutputBufferPtr
1139xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1140 xmlOutputBufferPtr ret;
1141
1142 if (fd < 0) return(NULL);
1143
1144 ret = xmlAllocOutputBuffer(encoder);
1145 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001146 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001147 ret->writecallback = xmlFdWrite;
1148 ret->closecallback = xmlFdClose;
1149 }
1150
1151 return(ret);
1152}
1153
1154/**
1155 * xmlParserInputBufferCreateIO:
1156 * @ioread: an I/O read function
1157 * @ioclose: an I/O close function
1158 * @ioctx: an I/O handler
1159 * @enc: the charset encoding if known
1160 *
1161 * Create a buffered parser input for the progressive parsing for the input
1162 * from an I/O handler
1163 *
1164 * Returns the new parser input or NULL
1165 */
1166xmlParserInputBufferPtr
1167xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1168 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1169 xmlParserInputBufferPtr ret;
1170
1171 if (ioread == NULL) return(NULL);
1172
1173 ret = xmlAllocParserInputBuffer(enc);
1174 if (ret != NULL) {
1175 ret->context = (void *) ioctx;
1176 ret->readcallback = ioread;
1177 ret->closecallback = ioclose;
1178 }
1179
1180 return(ret);
1181}
1182
1183/**
1184 * xmlOutputBufferCreateIO:
1185 * @iowrite: an I/O write function
1186 * @ioclose: an I/O close function
1187 * @ioctx: an I/O handler
1188 * @enc: the charset encoding if known
1189 *
1190 * Create a buffered output for the progressive saving
1191 * to an I/O handler
1192 *
1193 * Returns the new parser output or NULL
1194 */
1195xmlOutputBufferPtr
1196xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1197 xmlOutputCloseCallback ioclose, void *ioctx,
1198 xmlCharEncodingHandlerPtr encoder) {
1199 xmlOutputBufferPtr ret;
1200
1201 if (iowrite == NULL) return(NULL);
1202
1203 ret = xmlAllocOutputBuffer(encoder);
1204 if (ret != NULL) {
1205 ret->context = (void *) ioctx;
1206 ret->writecallback = iowrite;
1207 ret->closecallback = ioclose;
1208 }
1209
1210 return(ret);
1211}
1212
1213/**
1214 * xmlParserInputBufferPush:
1215 * @in: a buffered parser input
1216 * @len: the size in bytes of the array.
1217 * @buf: an char array
1218 *
1219 * Push the content of the arry in the input buffer
1220 * This routine handle the I18N transcoding to internal UTF-8
1221 * This is used when operating the parser in progressive (push) mode.
1222 *
1223 * Returns the number of chars read and stored in the buffer, or -1
1224 * in case of error.
1225 */
1226int
1227xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1228 int len, const char *buf) {
1229 int nbchars = 0;
1230
1231 if (len < 0) return(0);
1232 if (in->encoder != NULL) {
1233 /*
1234 * Store the data in the incoming raw buffer
1235 */
1236 if (in->raw == NULL) {
1237 in->raw = xmlBufferCreate();
1238 }
1239 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1240
1241 /*
1242 * convert as much as possible to the parser reading buffer.
1243 */
1244 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1245 if (nbchars < 0) {
1246 xmlGenericError(xmlGenericErrorContext,
1247 "xmlParserInputBufferPush: encoder error\n");
1248 return(-1);
1249 }
1250 } else {
1251 nbchars = len;
1252 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1253 }
1254#ifdef DEBUG_INPUT
1255 xmlGenericError(xmlGenericErrorContext,
1256 "I/O: pushed %d chars, buffer %d/%d\n",
1257 nbchars, in->buffer->use, in->buffer->size);
1258#endif
1259 return(nbchars);
1260}
1261
1262/**
1263 * xmlParserInputBufferGrow:
1264 * @in: a buffered parser input
1265 * @len: indicative value of the amount of chars to read
1266 *
1267 * Grow up the content of the input buffer, the old data are preserved
1268 * This routine handle the I18N transcoding to internal UTF-8
1269 * This routine is used when operating the parser in normal (pull) mode
1270 *
1271 * TODO: one should be able to remove one extra copy by copying directy
1272 * onto in->buffer or in->raw
1273 *
1274 * Returns the number of chars read and stored in the buffer, or -1
1275 * in case of error.
1276 */
1277int
1278xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1279 char *buffer = NULL;
1280 int res = 0;
1281 int nbchars = 0;
1282 int buffree;
1283
1284 if ((len <= MINLEN) && (len != 4))
1285 len = MINLEN;
1286 buffree = in->buffer->size - in->buffer->use;
1287 if (buffree <= 0) {
1288 xmlGenericError(xmlGenericErrorContext,
1289 "xmlParserInputBufferGrow : buffer full !\n");
1290 return(0);
1291 }
1292 if (len > buffree)
1293 len = buffree;
1294
1295 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
1296 if (buffer == NULL) {
1297 xmlGenericError(xmlGenericErrorContext,
1298 "xmlParserInputBufferGrow : out of memory !\n");
1299 return(-1);
1300 }
1301
1302 /*
1303 * Call the read method for this I/O type.
1304 */
1305 if (in->readcallback != NULL) {
1306 res = in->readcallback(in->context, &buffer[0], len);
1307 } else {
1308 xmlGenericError(xmlGenericErrorContext,
1309 "xmlParserInputBufferGrow : no input !\n");
1310 xmlFree(buffer);
1311 return(-1);
1312 }
1313 if (res < 0) {
1314 perror ("read error");
1315 xmlFree(buffer);
1316 return(-1);
1317 }
1318 len = res;
1319 if (in->encoder != NULL) {
1320 /*
1321 * Store the data in the incoming raw buffer
1322 */
1323 if (in->raw == NULL) {
1324 in->raw = xmlBufferCreate();
1325 }
1326 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
1327
1328 /*
1329 * convert as much as possible to the parser reading buffer.
1330 */
1331 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1332 if (nbchars < 0) {
1333 xmlGenericError(xmlGenericErrorContext,
1334 "xmlParserInputBufferGrow: encoder error\n");
1335 return(-1);
1336 }
1337 } else {
1338 nbchars = len;
1339 buffer[nbchars] = 0;
1340 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
1341 }
1342#ifdef DEBUG_INPUT
1343 xmlGenericError(xmlGenericErrorContext,
1344 "I/O: read %d chars, buffer %d/%d\n",
1345 nbchars, in->buffer->use, in->buffer->size);
1346#endif
1347 xmlFree(buffer);
1348 return(nbchars);
1349}
1350
1351/**
1352 * xmlParserInputBufferRead:
1353 * @in: a buffered parser input
1354 * @len: indicative value of the amount of chars to read
1355 *
1356 * Refresh the content of the input buffer, the old data are considered
1357 * consumed
1358 * This routine handle the I18N transcoding to internal UTF-8
1359 *
1360 * Returns the number of chars read and stored in the buffer, or -1
1361 * in case of error.
1362 */
1363int
1364xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1365 /* xmlBufferEmpty(in->buffer); */
1366 if (in->readcallback != NULL)
1367 return(xmlParserInputBufferGrow(in, len));
1368 else
1369 return(-1);
1370}
1371
1372/**
1373 * xmlOutputBufferWrite:
1374 * @out: a buffered parser output
1375 * @len: the size in bytes of the array.
1376 * @buf: an char array
1377 *
1378 * Write the content of the array in the output I/O buffer
1379 * This routine handle the I18N transcoding from internal UTF-8
1380 * The buffer is lossless, i.e. will store in case of partial
1381 * or delayed writes.
1382 *
1383 * Returns the number of chars immediately written, or -1
1384 * in case of error.
1385 */
1386int
1387xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
1388 int nbchars = 0; /* number of chars to output to I/O */
1389 int ret; /* return from function call */
1390 int written = 0; /* number of char written to I/O so far */
1391 int chunk; /* number of byte curreent processed from buf */
1392
1393 if (len < 0) return(0);
1394
1395 do {
1396 chunk = len;
1397 if (chunk > 4 * MINLEN)
1398 chunk = 4 * MINLEN;
1399
1400 /*
1401 * first handle encoding stuff.
1402 */
1403 if (out->encoder != NULL) {
1404 /*
1405 * Store the data in the incoming raw buffer
1406 */
1407 if (out->conv == NULL) {
1408 out->conv = xmlBufferCreate();
1409 }
1410 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
1411
1412 if ((out->buffer->use < MINLEN) && (chunk == len))
1413 goto done;
1414
1415 /*
1416 * convert as much as possible to the parser reading buffer.
1417 */
1418 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1419 if (ret < 0) {
1420 xmlGenericError(xmlGenericErrorContext,
1421 "xmlOutputBufferWrite: encoder error\n");
1422 return(-1);
1423 }
1424 nbchars = out->conv->use;
1425 } else {
1426 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
1427 nbchars = out->buffer->use;
1428 }
1429 buf += chunk;
1430 len -= chunk;
1431
1432 if ((nbchars < MINLEN) && (len <= 0))
1433 goto done;
1434
1435 if (out->writecallback) {
1436 /*
1437 * second write the stuff to the I/O channel
1438 */
1439 if (out->encoder != NULL) {
1440 ret = out->writecallback(out->context,
1441 (const char *)out->conv->content, nbchars);
1442 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00001443 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001444 } else {
1445 ret = out->writecallback(out->context,
1446 (const char *)out->buffer->content, nbchars);
1447 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00001448 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001449 }
1450 if (ret < 0) {
1451 xmlGenericError(xmlGenericErrorContext,
1452 "I/O: error %d writing %d bytes\n", ret, nbchars);
1453 return(ret);
1454 }
1455 out->written += ret;
1456 }
1457 written += nbchars;
1458 } while (len > 0);
1459
1460done:
1461#ifdef DEBUG_INPUT
1462 xmlGenericError(xmlGenericErrorContext,
1463 "I/O: wrote %d chars\n", written);
1464#endif
1465 return(written);
1466}
1467
1468/**
1469 * xmlOutputBufferWriteString:
1470 * @out: a buffered parser output
1471 * @str: a zero terminated C string
1472 *
1473 * Write the content of the string in the output I/O buffer
1474 * This routine handle the I18N transcoding from internal UTF-8
1475 * The buffer is lossless, i.e. will store in case of partial
1476 * or delayed writes.
1477 *
1478 * Returns the number of chars immediately written, or -1
1479 * in case of error.
1480 */
1481int
1482xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
1483 int len;
1484
1485 if (str == NULL)
1486 return(-1);
1487 len = strlen(str);
1488
1489 if (len > 0)
1490 return(xmlOutputBufferWrite(out, len, str));
1491 return(len);
1492}
1493
1494/**
1495 * xmlOutputBufferFlush:
1496 * @out: a buffered output
1497 *
1498 * flushes the output I/O channel
1499 *
1500 * Returns the number of byte written or -1 in case of error.
1501 */
1502int
1503xmlOutputBufferFlush(xmlOutputBufferPtr out) {
1504 int nbchars = 0, ret = 0;
1505
1506 /*
1507 * first handle encoding stuff.
1508 */
1509 if ((out->conv != NULL) && (out->encoder != NULL)) {
1510 /*
1511 * convert as much as possible to the parser reading buffer.
1512 */
1513 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1514 if (nbchars < 0) {
1515 xmlGenericError(xmlGenericErrorContext,
1516 "xmlOutputBufferWrite: encoder error\n");
1517 return(-1);
1518 }
1519 }
1520
1521 /*
1522 * second flush the stuff to the I/O channel
1523 */
1524 if ((out->conv != NULL) && (out->encoder != NULL) &&
1525 (out->writecallback != NULL)) {
1526 ret = out->writecallback(out->context,
1527 (const char *)out->conv->content, out->conv->use);
1528 if (ret >= 0)
1529 xmlBufferShrink(out->conv, ret);
1530 } else if (out->writecallback != NULL) {
1531 ret = out->writecallback(out->context,
1532 (const char *)out->buffer->content, out->buffer->use);
1533 if (ret >= 0)
1534 xmlBufferShrink(out->buffer, ret);
1535 }
1536 if (ret < 0) {
1537 xmlGenericError(xmlGenericErrorContext,
1538 "I/O: error %d flushing %d bytes\n", ret, nbchars);
1539 return(ret);
1540 }
1541 out->written += ret;
1542
1543#ifdef DEBUG_INPUT
1544 xmlGenericError(xmlGenericErrorContext,
1545 "I/O: flushed %d chars\n", ret);
1546#endif
1547 return(ret);
1548}
1549
1550/*
1551 * xmlParserGetDirectory:
1552 * @filename: the path to a file
1553 *
1554 * lookup the directory for that file
1555 *
1556 * Returns a new allocated string containing the directory, or NULL.
1557 */
1558char *
1559xmlParserGetDirectory(const char *filename) {
1560 char *ret = NULL;
1561 char dir[1024];
1562 char *cur;
1563 char sep = '/';
1564
1565 if (xmlInputCallbackInitialized == 0)
1566 xmlRegisterDefaultInputCallbacks();
1567
1568 if (filename == NULL) return(NULL);
1569#ifdef WIN32
1570 sep = '\\';
1571#endif
1572
1573 strncpy(dir, filename, 1023);
1574 dir[1023] = 0;
1575 cur = &dir[strlen(dir)];
1576 while (cur > dir) {
1577 if (*cur == sep) break;
1578 cur --;
1579 }
1580 if (*cur == sep) {
1581 if (cur == dir) dir[1] = 0;
1582 else *cur = 0;
1583 ret = xmlMemStrdup(dir);
1584 } else {
1585 if (getcwd(dir, 1024) != NULL) {
1586 dir[1023] = 0;
1587 ret = xmlMemStrdup(dir);
1588 }
1589 }
1590 return(ret);
1591}
1592
1593/****************************************************************
1594 * *
1595 * External entities loading *
1596 * *
1597 ****************************************************************/
1598
1599/*
1600 * xmlDefaultExternalEntityLoader:
1601 * @URL: the URL for the entity to load
1602 * @ID: the System ID for the entity to load
1603 * @ctxt: the context in which the entity is called or NULL
1604 *
1605 * By default we don't load external entitites, yet.
1606 *
1607 * Returns a new allocated xmlParserInputPtr, or NULL.
1608 */
1609static
1610xmlParserInputPtr
1611xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
1612 xmlParserCtxtPtr ctxt) {
1613 xmlParserInputPtr ret = NULL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001614 const xmlChar *resource = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001615
1616#ifdef DEBUG_EXTERNAL_ENTITIES
1617 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard4d65a1c2001-07-04 22:06:23 +00001618 "xmlDefaultExternalEntityLoader(%s, %s)\n", URL, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00001619#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001620#ifdef LIBXML_CATALOG_ENABLED
1621 /*
1622 * Try to load it from the resource pointed in the catalog
1623 */
1624 if (ID != NULL)
1625 resource = xmlCatalogGetPublic((const xmlChar *)ID);
1626 if ((resource == NULL) && (URL != NULL))
1627 resource = xmlCatalogGetSystem((const xmlChar *)URL);
1628#endif
1629
1630 if (resource == NULL)
1631 resource = (const xmlChar *)URL;
1632
1633 if (resource == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00001634 if ((ctxt->validate) && (ctxt->sax != NULL) &&
1635 (ctxt->sax->error != NULL))
1636 ctxt->sax->error(ctxt,
1637 "failed to load external entity \"%s\"\n", ID);
1638 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001639 ctxt->sax->warning(ctxt,
1640 "failed to load external entity \"%s\"\n", ID);
1641 return(NULL);
1642 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001643 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00001644 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00001645 if ((ctxt->validate) && (ctxt->sax != NULL) &&
1646 (ctxt->sax->error != NULL))
1647 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001648 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00001649 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001650 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00001651 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00001652 }
1653 return(ret);
1654}
1655
1656static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1657 xmlDefaultExternalEntityLoader;
1658
1659/*
1660 * xmlSetExternalEntityLoader:
1661 * @f: the new entity resolver function
1662 *
1663 * Changes the defaultexternal entity resolver function for the application
1664 */
1665void
1666xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1667 xmlCurrentExternalEntityLoader = f;
1668}
1669
1670/*
1671 * xmlGetExternalEntityLoader:
1672 *
1673 * Get the default external entity resolver function for the application
1674 *
1675 * Returns the xmlExternalEntityLoader function pointer
1676 */
1677xmlExternalEntityLoader
1678xmlGetExternalEntityLoader(void) {
1679 return(xmlCurrentExternalEntityLoader);
1680}
1681
1682/*
1683 * xmlLoadExternalEntity:
1684 * @URL: the URL for the entity to load
1685 * @ID: the System ID for the entity to load
1686 * @ctxt: the context in which the entity is called or NULL
1687 *
1688 * Load an external entity, note that the use of this function for
1689 * unparsed entities may generate problems
1690 * TODO: a more generic External entitiy API must be designed
1691 *
1692 * Returns the xmlParserInputPtr or NULL
1693 */
1694xmlParserInputPtr
1695xmlLoadExternalEntity(const char *URL, const char *ID,
1696 xmlParserCtxtPtr ctxt) {
1697 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
1698}
1699