blob: 7eba615710471528b1bc1274b9abb8d25af4f8fe [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 *
6 * Daniel.Veillard@w3.org
7 *
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>
65#include <libxml/nanohttp.h>
66#include <libxml/nanoftp.h>
67#include <libxml/xmlerror.h>
68
69#ifdef VMS
70#define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
71#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
72#endif
73
74/* #define VERBOSE_FAILURE */
75/* #define DEBUG_EXTERNAL_ENTITIES */
76/* #define DEBUG_INPUT */
77
78#ifdef DEBUG_INPUT
79#define MINLEN 40
80#else
81#define MINLEN 4000
82#endif
83
84/*
85 * Input I/O callback sets
86 */
87typedef struct _xmlInputCallback {
88 xmlInputMatchCallback matchcallback;
89 xmlInputOpenCallback opencallback;
90 xmlInputReadCallback readcallback;
91 xmlInputCloseCallback closecallback;
92} xmlInputCallback;
93
94#define MAX_INPUT_CALLBACK 15
95
96xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
97int xmlInputCallbackNr = 0;
98int xmlInputCallbackInitialized = 0;
99
100/*
101 * Output I/O callback sets
102 */
103typedef struct _xmlOutputCallback {
104 xmlOutputMatchCallback matchcallback;
105 xmlOutputOpenCallback opencallback;
106 xmlOutputWriteCallback writecallback;
107 xmlOutputCloseCallback closecallback;
108} xmlOutputCallback;
109
110#define MAX_OUTPUT_CALLBACK 15
111
112xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
113int xmlOutputCallbackNr = 0;
114int xmlOutputCallbackInitialized = 0;
115
116/************************************************************************
117 * *
118 * Standard I/O for file accesses *
119 * *
120 ************************************************************************/
121
122/**
123 * xmlCheckFilename
124 * @path: the path to check
125 *
126 * function checks to see if @path is a valid source
127 * (file, socket...) for XML.
128 *
129 * if stat is not available on the target machine,
130 * returns 1. if stat fails, returns 0 (if calling
131 * stat on the filename fails, it can't be right).
132 * if stat succeeds and the file is a directory,
133 * sets errno to EISDIR and returns 0. otherwise
134 * returns 1.
135 */
136
137static int
138xmlCheckFilename (const char *path)
139{
140#ifdef HAVE_STAT
141#ifdef S_ISDIR
142 struct stat stat_buffer;
143
144 if (stat(path, &stat_buffer) == -1)
145 return 0;
146
147 if (S_ISDIR(stat_buffer.st_mode)) {
148 errno = EISDIR;
149 return 0;
150 }
151
152#endif
153#endif
154 return 1;
155}
156
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000157static int
Owen Taylor3473f882001-02-23 17:55:21 +0000158xmlNop(void) {
159 return(0);
160}
161
162/**
Owen Taylor3473f882001-02-23 17:55:21 +0000163 * xmlFdRead:
164 * @context: the I/O context
165 * @buffer: where to drop data
166 * @len: number of bytes to read
167 *
168 * Read @len bytes to @buffer from the I/O channel.
169 *
170 * Returns the number of bytes written
171 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000172static int
Owen Taylor3473f882001-02-23 17:55:21 +0000173xmlFdRead (void * context, char * buffer, int len) {
174 return(read((int) context, &buffer[0], len));
175}
176
177/**
178 * xmlFdWrite:
179 * @context: the I/O context
180 * @buffer: where to get data
181 * @len: number of bytes to write
182 *
183 * Write @len bytes from @buffer to the I/O channel.
184 *
185 * Returns the number of bytes written
186 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000187static int
Owen Taylor3473f882001-02-23 17:55:21 +0000188xmlFdWrite (void * context, const char * buffer, int len) {
189 return(write((int) context, &buffer[0], len));
190}
191
192/**
193 * xmlFdClose:
194 * @context: the I/O context
195 *
196 * Close an I/O channel
197 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000198static void
Owen Taylor3473f882001-02-23 17:55:21 +0000199xmlFdClose (void * context) {
200 close((int) context);
201}
202
203/**
204 * xmlFileMatch:
205 * @filename: the URI for matching
206 *
207 * input from FILE *
208 *
209 * Returns 1 if matches, 0 otherwise
210 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000211static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000212xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000213 return(1);
214}
215
216/**
217 * xmlFileOpen:
218 * @filename: the URI for matching
219 *
220 * input from FILE *, supports compressed input
221 * if @filename is " " then the standard input is used
222 *
223 * Returns an I/O context or NULL in case of error
224 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000225static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000226xmlFileOpen (const char *filename) {
227 const char *path = NULL;
228 FILE *fd;
229
230 if (!strcmp(filename, "-")) {
231 fd = stdin;
232 return((void *) fd);
233 }
234
235 if (!strncmp(filename, "file://localhost", 16))
236 path = &filename[16];
237 else if (!strncmp(filename, "file:///", 8))
238 path = &filename[8];
239 else
240 path = filename;
241
242 if (path == NULL)
243 return(NULL);
244 if (!xmlCheckFilename(path))
245 return(NULL);
246
247#ifdef WIN32
248 fd = fopen(path, "rb");
249#else
250 fd = fopen(path, "r");
251#endif /* WIN32 */
252 return((void *) fd);
253}
254
255/**
256 * xmlFileOpenW:
257 * @filename: the URI for matching
258 *
259 * output to from FILE *,
260 * if @filename is "-" then the standard output is used
261 *
262 * Returns an I/O context or NULL in case of error
263 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000264static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000265xmlFileOpenW (const char *filename) {
266 const char *path = NULL;
267 FILE *fd;
268
269 if (!strcmp(filename, "-")) {
270 fd = stdout;
271 return((void *) fd);
272 }
273
274 if (!strncmp(filename, "file://localhost", 16))
275 path = &filename[16];
276 else if (!strncmp(filename, "file:///", 8))
277 path = &filename[8];
278 else
279 path = filename;
280
281 if (path == NULL)
282 return(NULL);
283
284 fd = fopen(path, "w");
285 return((void *) fd);
286}
287
288/**
289 * xmlFileRead:
290 * @context: the I/O context
291 * @buffer: where to drop data
292 * @len: number of bytes to write
293 *
294 * Read @len bytes to @buffer from the I/O channel.
295 *
296 * Returns the number of bytes written
297 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000298static int
Owen Taylor3473f882001-02-23 17:55:21 +0000299xmlFileRead (void * context, char * buffer, int len) {
300 return(fread(&buffer[0], 1, len, (FILE *) context));
301}
302
303/**
304 * xmlFileWrite:
305 * @context: the I/O context
306 * @buffer: where to drop data
307 * @len: number of bytes to write
308 *
309 * Write @len bytes from @buffer to the I/O channel.
310 *
311 * Returns the number of bytes written
312 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000313static int
Owen Taylor3473f882001-02-23 17:55:21 +0000314xmlFileWrite (void * context, const char * buffer, int len) {
315 return(fwrite(&buffer[0], 1, len, (FILE *) context));
316}
317
318/**
319 * xmlFileClose:
320 * @context: the I/O context
321 *
322 * Close an I/O channel
323 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000324static void
Owen Taylor3473f882001-02-23 17:55:21 +0000325xmlFileClose (void * context) {
326 fclose((FILE *) context);
327}
328
329/**
330 * xmlFileFlush:
331 * @context: the I/O context
332 *
333 * Flush an I/O channel
334 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000335static void
Owen Taylor3473f882001-02-23 17:55:21 +0000336xmlFileFlush (void * context) {
337 fflush((FILE *) context);
338}
339
340#ifdef HAVE_ZLIB_H
341/************************************************************************
342 * *
343 * I/O for compressed file accesses *
344 * *
345 ************************************************************************/
346/**
347 * xmlGzfileMatch:
348 * @filename: the URI for matching
349 *
350 * input from compressed file test
351 *
352 * Returns 1 if matches, 0 otherwise
353 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000354static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000355xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000356 return(1);
357}
358
359/**
360 * xmlGzfileOpen:
361 * @filename: the URI for matching
362 *
363 * input from compressed file open
364 * if @filename is " " then the standard input is used
365 *
366 * Returns an I/O context or NULL in case of error
367 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000368static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000369xmlGzfileOpen (const char *filename) {
370 const char *path = NULL;
371 gzFile fd;
372
373 if (!strcmp(filename, "-")) {
374 fd = gzdopen(fileno(stdin), "rb");
375 return((void *) fd);
376 }
377
378 if (!strncmp(filename, "file://localhost", 16))
379 path = &filename[16];
380 else if (!strncmp(filename, "file:///", 8))
381 path = &filename[7];
382 else
383 path = filename;
384
385 if (path == NULL)
386 return(NULL);
387 if (!xmlCheckFilename(path))
388 return(NULL);
389
390 fd = gzopen(path, "rb");
391 return((void *) fd);
392}
393
394/**
395 * xmlGzfileOpenW:
396 * @filename: the URI for matching
397 * @compression: the compression factor (0 - 9 included)
398 *
399 * input from compressed file open
400 * if @filename is " " then the standard input is used
401 *
402 * Returns an I/O context or NULL in case of error
403 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000404static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000405xmlGzfileOpenW (const char *filename, int compression) {
406 const char *path = NULL;
407 char mode[15];
408 gzFile fd;
409
410 sprintf(mode, "wb%d", compression);
411 if (!strcmp(filename, "-")) {
412 fd = gzdopen(1, mode);
413 return((void *) fd);
414 }
415
416 if (!strncmp(filename, "file://localhost", 16))
417 path = &filename[16];
418 else if (!strncmp(filename, "file:///", 8))
419 path = &filename[8];
420 else
421 path = filename;
422
423 if (path == NULL)
424 return(NULL);
425
426 fd = gzopen(path, mode);
427 return((void *) fd);
428}
429
430/**
431 * xmlGzfileRead:
432 * @context: the I/O context
433 * @buffer: where to drop data
434 * @len: number of bytes to write
435 *
436 * Read @len bytes to @buffer from the compressed I/O channel.
437 *
438 * Returns the number of bytes written
439 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000440static int
Owen Taylor3473f882001-02-23 17:55:21 +0000441xmlGzfileRead (void * context, char * buffer, int len) {
442 return(gzread((gzFile) context, &buffer[0], len));
443}
444
445/**
446 * xmlGzfileWrite:
447 * @context: the I/O context
448 * @buffer: where to drop data
449 * @len: number of bytes to write
450 *
451 * Write @len bytes from @buffer to the compressed I/O channel.
452 *
453 * Returns the number of bytes written
454 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000455static int
Owen Taylor3473f882001-02-23 17:55:21 +0000456xmlGzfileWrite (void * context, const char * buffer, int len) {
457 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
458}
459
460/**
461 * xmlGzfileClose:
462 * @context: the I/O context
463 *
464 * Close a compressed I/O channel
465 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000466static void
Owen Taylor3473f882001-02-23 17:55:21 +0000467xmlGzfileClose (void * context) {
468 gzclose((gzFile) context);
469}
470#endif /* HAVE_ZLIB_H */
471
472#ifdef LIBXML_HTTP_ENABLED
473/************************************************************************
474 * *
475 * I/O for HTTP file accesses *
476 * *
477 ************************************************************************/
478/**
479 * xmlIOHTTPMatch:
480 * @filename: the URI for matching
481 *
482 * check if the URI matches an HTTP one
483 *
484 * Returns 1 if matches, 0 otherwise
485 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000486static int
Owen Taylor3473f882001-02-23 17:55:21 +0000487xmlIOHTTPMatch (const char *filename) {
488 if (!strncmp(filename, "http://", 7))
489 return(1);
490 return(0);
491}
492
493/**
494 * xmlIOHTTPOpen:
495 * @filename: the URI for matching
496 *
497 * open an HTTP I/O channel
498 *
499 * Returns an I/O context or NULL in case of error
500 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000501static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000502xmlIOHTTPOpen (const char *filename) {
503 return(xmlNanoHTTPOpen(filename, NULL));
504}
505
506/**
507 * xmlIOHTTPRead:
508 * @context: the I/O context
509 * @buffer: where to drop data
510 * @len: number of bytes to write
511 *
512 * Read @len bytes to @buffer from the I/O channel.
513 *
514 * Returns the number of bytes written
515 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000516static int
Owen Taylor3473f882001-02-23 17:55:21 +0000517xmlIOHTTPRead(void * context, char * buffer, int len) {
518 return(xmlNanoHTTPRead(context, &buffer[0], len));
519}
520
521/**
522 * xmlIOHTTPClose:
523 * @context: the I/O context
524 *
525 * Close an HTTP I/O channel
526 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000527static void
Owen Taylor3473f882001-02-23 17:55:21 +0000528xmlIOHTTPClose (void * context) {
529 xmlNanoHTTPClose(context);
530}
531#endif /* LIBXML_HTTP_ENABLED */
532
533#ifdef LIBXML_FTP_ENABLED
534/************************************************************************
535 * *
536 * I/O for FTP file accesses *
537 * *
538 ************************************************************************/
539/**
540 * xmlIOFTPMatch:
541 * @filename: the URI for matching
542 *
543 * check if the URI matches an FTP one
544 *
545 * Returns 1 if matches, 0 otherwise
546 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000547static int
Owen Taylor3473f882001-02-23 17:55:21 +0000548xmlIOFTPMatch (const char *filename) {
549 if (!strncmp(filename, "ftp://", 6))
550 return(1);
551 return(0);
552}
553
554/**
555 * xmlIOFTPOpen:
556 * @filename: the URI for matching
557 *
558 * open an FTP I/O channel
559 *
560 * Returns an I/O context or NULL in case of error
561 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000562static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000563xmlIOFTPOpen (const char *filename) {
564 return(xmlNanoFTPOpen(filename));
565}
566
567/**
568 * xmlIOFTPRead:
569 * @context: the I/O context
570 * @buffer: where to drop data
571 * @len: number of bytes to write
572 *
573 * Read @len bytes to @buffer from the I/O channel.
574 *
575 * Returns the number of bytes written
576 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000577static int
Owen Taylor3473f882001-02-23 17:55:21 +0000578xmlIOFTPRead(void * context, char * buffer, int len) {
579 return(xmlNanoFTPRead(context, &buffer[0], len));
580}
581
582/**
583 * xmlIOFTPClose:
584 * @context: the I/O context
585 *
586 * Close an FTP I/O channel
587 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000588static void
Owen Taylor3473f882001-02-23 17:55:21 +0000589xmlIOFTPClose (void * context) {
590 xmlNanoFTPClose(context);
591}
592#endif /* LIBXML_FTP_ENABLED */
593
594
595/**
596 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000597 * @matchFunc: the xmlInputMatchCallback
598 * @openFunc: the xmlInputOpenCallback
599 * @readFunc: the xmlInputReadCallback
600 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +0000601 *
602 * Register a new set of I/O callback for handling parser input.
603 *
604 * Returns the registered handler number or -1 in case of error
605 */
606int
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000607xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
608 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
609 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +0000610 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
611 return(-1);
612 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000613 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
614 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
615 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
616 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000617 return(xmlInputCallbackNr++);
618}
619
620/**
621 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000622 * @matchFunc: the xmlOutputMatchCallback
623 * @openFunc: the xmlOutputOpenCallback
624 * @writeFunc: the xmlOutputWriteCallback
625 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +0000626 *
627 * Register a new set of I/O callback for handling output.
628 *
629 * Returns the registered handler number or -1 in case of error
630 */
631int
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000632xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
633 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
634 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +0000635 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
636 return(-1);
637 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000638 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
639 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
640 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
641 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000642 return(xmlOutputCallbackNr++);
643}
644
645/**
646 * xmlRegisterDefaultInputCallbacks:
647 *
648 * Registers the default compiled-in I/O handlers.
649 */
650void
651#ifdef VMS
652xmlRegisterDefInputCallbacks
653#else
654xmlRegisterDefaultInputCallbacks
655#endif
656(void) {
657 if (xmlInputCallbackInitialized)
658 return;
659
660 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
661 xmlFileRead, xmlFileClose);
662#ifdef HAVE_ZLIB_H
663 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
664 xmlGzfileRead, xmlGzfileClose);
665#endif /* HAVE_ZLIB_H */
666
667#ifdef LIBXML_HTTP_ENABLED
668 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
669 xmlIOHTTPRead, xmlIOHTTPClose);
670#endif /* LIBXML_HTTP_ENABLED */
671
672#ifdef LIBXML_FTP_ENABLED
673 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
674 xmlIOFTPRead, xmlIOFTPClose);
675#endif /* LIBXML_FTP_ENABLED */
676 xmlInputCallbackInitialized = 1;
677}
678
679/**
680 * xmlRegisterDefaultOutputCallbacks:
681 *
682 * Registers the default compiled-in I/O handlers.
683 */
684void
685#ifdef VMS
686xmlRegisterDefOutputCallbacks
687#else
688xmlRegisterDefaultOutputCallbacks
689#endif
690(void) {
691 if (xmlOutputCallbackInitialized)
692 return;
693
694 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
695 xmlFileWrite, xmlFileClose);
696/*********************************
697 No way a-priori to distinguish between gzipped files from
698 uncompressed ones except opening if existing then closing
699 and saving with same compression ratio ... a pain.
700
701#ifdef HAVE_ZLIB_H
702 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
703 xmlGzfileWrite, xmlGzfileClose);
704#endif
705 No HTTP PUT support yet, patches welcome
706
707#ifdef LIBXML_HTTP_ENABLED
708 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
709 xmlIOHTTPWrite, xmlIOHTTPClose);
710#endif
711
712 Nor FTP PUT ....
713#ifdef LIBXML_FTP_ENABLED
714 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
715 xmlIOFTPWrite, xmlIOFTPClose);
716#endif
717 **********************************/
718 xmlOutputCallbackInitialized = 1;
719}
720
721/**
722 * xmlAllocParserInputBuffer:
723 * @enc: the charset encoding if known
724 *
725 * Create a buffered parser input for progressive parsing
726 *
727 * Returns the new parser input or NULL
728 */
729xmlParserInputBufferPtr
730xmlAllocParserInputBuffer(xmlCharEncoding enc) {
731 xmlParserInputBufferPtr ret;
732
733 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
734 if (ret == NULL) {
735 xmlGenericError(xmlGenericErrorContext,
736 "xmlAllocParserInputBuffer : out of memory!\n");
737 return(NULL);
738 }
739 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
740 ret->buffer = xmlBufferCreate();
741 if (ret->buffer == NULL) {
742 xmlFree(ret);
743 return(NULL);
744 }
745 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
746 ret->encoder = xmlGetCharEncodingHandler(enc);
747 if (ret->encoder != NULL)
748 ret->raw = xmlBufferCreate();
749 else
750 ret->raw = NULL;
751 ret->readcallback = NULL;
752 ret->closecallback = NULL;
753 ret->context = NULL;
754
755 return(ret);
756}
757
758/**
759 * xmlAllocOutputBuffer:
760 * @encoder: the encoding converter or NULL
761 *
762 * Create a buffered parser output
763 *
764 * Returns the new parser output or NULL
765 */
766xmlOutputBufferPtr
767xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
768 xmlOutputBufferPtr ret;
769
770 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
771 if (ret == NULL) {
772 xmlGenericError(xmlGenericErrorContext,
773 "xmlAllocOutputBuffer : out of memory!\n");
774 return(NULL);
775 }
776 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
777 ret->buffer = xmlBufferCreate();
778 if (ret->buffer == NULL) {
779 xmlFree(ret);
780 return(NULL);
781 }
782 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
783 ret->encoder = encoder;
784 if (encoder != NULL) {
785 ret->conv = xmlBufferCreateSize(4000);
786 /*
787 * This call is designed to initiate the encoder state
788 */
789 xmlCharEncOutFunc(encoder, ret->conv, NULL);
790 } else
791 ret->conv = NULL;
792 ret->writecallback = NULL;
793 ret->closecallback = NULL;
794 ret->context = NULL;
795 ret->written = 0;
796
797 return(ret);
798}
799
800/**
801 * xmlFreeParserInputBuffer:
802 * @in: a buffered parser input
803 *
804 * Free up the memory used by a buffered parser input
805 */
806void
807xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
808 if (in->raw) {
809 xmlBufferFree(in->raw);
810 in->raw = NULL;
811 }
812 if (in->encoder != NULL) {
813 xmlCharEncCloseFunc(in->encoder);
814 }
815 if (in->closecallback != NULL) {
816 in->closecallback(in->context);
817 }
818 if (in->buffer != NULL) {
819 xmlBufferFree(in->buffer);
820 in->buffer = NULL;
821 }
822
Owen Taylor3473f882001-02-23 17:55:21 +0000823 xmlFree(in);
824}
825
826/**
827 * xmlOutputBufferClose:
828 * @out: a buffered output
829 *
830 * flushes and close the output I/O channel
831 * and free up all the associated resources
832 *
833 * Returns the number of byte written or -1 in case of error.
834 */
835int
836xmlOutputBufferClose(xmlOutputBufferPtr out) {
837 int written;
838
839 if (out == NULL)
840 return(-1);
841 if (out->writecallback != NULL)
842 xmlOutputBufferFlush(out);
843 if (out->closecallback != NULL) {
844 out->closecallback(out->context);
845 }
846 written = out->written;
847 if (out->conv) {
848 xmlBufferFree(out->conv);
849 out->conv = NULL;
850 }
851 if (out->encoder != NULL) {
852 xmlCharEncCloseFunc(out->encoder);
853 }
854 if (out->buffer != NULL) {
855 xmlBufferFree(out->buffer);
856 out->buffer = NULL;
857 }
858
Owen Taylor3473f882001-02-23 17:55:21 +0000859 xmlFree(out);
860 return(written);
861}
862
863/**
864 * xmlParserInputBufferCreateFilename:
865 * @URI: a C string containing the URI or filename
866 * @enc: the charset encoding if known
867 *
868 * Create a buffered parser input for the progressive parsing of a file
869 * If filename is "-' then we use stdin as the input.
870 * Automatic support for ZLIB/Compress compressed document is provided
871 * by default if found at compile-time.
872 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
873 *
874 * Returns the new parser input or NULL
875 */
876xmlParserInputBufferPtr
877#ifdef VMS
878xmlParserInputBufferCreateFname
879#else
880xmlParserInputBufferCreateFilename
881#endif
882(const char *URI, xmlCharEncoding enc) {
883 xmlParserInputBufferPtr ret;
884 int i;
885 void *context = NULL;
886
887 if (xmlInputCallbackInitialized == 0)
888 xmlRegisterDefaultInputCallbacks();
889
890 if (URI == NULL) return(NULL);
891
892 /*
893 * Try to find one of the input accept method accepting taht scheme
894 * Go in reverse to give precedence to user defined handlers.
895 */
896 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
897 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
898 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
899 context = xmlInputCallbackTable[i].opencallback(URI);
900 if (context != NULL)
901 break;
902 }
903 }
904 if (context == NULL) {
905 return(NULL);
906 }
907
908 /*
909 * Allocate the Input buffer front-end.
910 */
911 ret = xmlAllocParserInputBuffer(enc);
912 if (ret != NULL) {
913 ret->context = context;
914 ret->readcallback = xmlInputCallbackTable[i].readcallback;
915 ret->closecallback = xmlInputCallbackTable[i].closecallback;
916 }
917 return(ret);
918}
919
920/**
921 * xmlOutputBufferCreateFilename:
922 * @URI: a C string containing the URI or filename
923 * @encoder: the encoding converter or NULL
924 * @compression: the compression ration (0 none, 9 max).
925 *
926 * Create a buffered output for the progressive saving of a file
927 * If filename is "-' then we use stdout as the output.
928 * Automatic support for ZLIB/Compress compressed document is provided
929 * by default if found at compile-time.
930 * TODO: currently if compression is set, the library only support
931 * writing to a local file.
932 *
933 * Returns the new output or NULL
934 */
935xmlOutputBufferPtr
936xmlOutputBufferCreateFilename(const char *URI,
937 xmlCharEncodingHandlerPtr encoder,
938 int compression) {
939 xmlOutputBufferPtr ret;
940 int i;
941 void *context = NULL;
942
943 if (xmlOutputCallbackInitialized == 0)
944 xmlRegisterDefaultOutputCallbacks();
945
946 if (URI == NULL) return(NULL);
947
948#ifdef HAVE_ZLIB_H
949 if ((compression > 0) && (compression <= 9)) {
950 context = xmlGzfileOpenW(URI, compression);
951 if (context != NULL) {
952 ret = xmlAllocOutputBuffer(encoder);
953 if (ret != NULL) {
954 ret->context = context;
955 ret->writecallback = xmlGzfileWrite;
956 ret->closecallback = xmlGzfileClose;
957 }
958 return(ret);
959 }
960 }
961#endif
962
963 /*
964 * Try to find one of the output accept method accepting taht scheme
965 * Go in reverse to give precedence to user defined handlers.
966 */
967 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
968 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
969 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
970 context = xmlOutputCallbackTable[i].opencallback(URI);
971 if (context != NULL)
972 break;
973 }
974 }
975 if (context == NULL) {
976 return(NULL);
977 }
978
979 /*
980 * Allocate the Output buffer front-end.
981 */
982 ret = xmlAllocOutputBuffer(encoder);
983 if (ret != NULL) {
984 ret->context = context;
985 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
986 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
987 }
988 return(ret);
989}
990
991/**
992 * xmlParserInputBufferCreateFile:
993 * @file: a FILE*
994 * @enc: the charset encoding if known
995 *
996 * Create a buffered parser input for the progressive parsing of a FILE *
997 * buffered C I/O
998 *
999 * Returns the new parser input or NULL
1000 */
1001xmlParserInputBufferPtr
1002xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1003 xmlParserInputBufferPtr ret;
1004
1005 if (xmlInputCallbackInitialized == 0)
1006 xmlRegisterDefaultInputCallbacks();
1007
1008 if (file == NULL) return(NULL);
1009
1010 ret = xmlAllocParserInputBuffer(enc);
1011 if (ret != NULL) {
1012 ret->context = file;
1013 ret->readcallback = xmlFileRead;
1014 ret->closecallback = xmlFileFlush;
1015 }
1016
1017 return(ret);
1018}
1019
1020/**
1021 * xmlOutputBufferCreateFile:
1022 * @file: a FILE*
1023 * @encoder: the encoding converter or NULL
1024 *
1025 * Create a buffered output for the progressive saving to a FILE *
1026 * buffered C I/O
1027 *
1028 * Returns the new parser output or NULL
1029 */
1030xmlOutputBufferPtr
1031xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1032 xmlOutputBufferPtr ret;
1033
1034 if (xmlOutputCallbackInitialized == 0)
1035 xmlRegisterDefaultOutputCallbacks();
1036
1037 if (file == NULL) return(NULL);
1038
1039 ret = xmlAllocOutputBuffer(encoder);
1040 if (ret != NULL) {
1041 ret->context = file;
1042 ret->writecallback = xmlFileWrite;
1043 ret->closecallback = xmlFileFlush;
1044 }
1045
1046 return(ret);
1047}
1048
1049/**
1050 * xmlParserInputBufferCreateFd:
1051 * @fd: a file descriptor number
1052 * @enc: the charset encoding if known
1053 *
1054 * Create a buffered parser input for the progressive parsing for the input
1055 * from a file descriptor
1056 *
1057 * Returns the new parser input or NULL
1058 */
1059xmlParserInputBufferPtr
1060xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1061 xmlParserInputBufferPtr ret;
1062
1063 if (fd < 0) return(NULL);
1064
1065 ret = xmlAllocParserInputBuffer(enc);
1066 if (ret != NULL) {
1067 ret->context = (void *) fd;
1068 ret->readcallback = xmlFdRead;
1069 ret->closecallback = xmlFdClose;
1070 }
1071
1072 return(ret);
1073}
1074
1075/**
1076 * xmlParserInputBufferCreateMem:
1077 * @mem: the memory input
1078 * @size: the length of the memory block
1079 * @enc: the charset encoding if known
1080 *
1081 * Create a buffered parser input for the progressive parsing for the input
1082 * from a memory area.
1083 *
1084 * Returns the new parser input or NULL
1085 */
1086xmlParserInputBufferPtr
1087xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1088 xmlParserInputBufferPtr ret;
1089
1090 if (size <= 0) return(NULL);
1091 if (mem == NULL) return(NULL);
1092
1093 ret = xmlAllocParserInputBuffer(enc);
1094 if (ret != NULL) {
1095 ret->context = (void *) mem;
1096 ret->readcallback = (xmlInputReadCallback) xmlNop;
1097 ret->closecallback = NULL;
1098 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1099 }
1100
1101 return(ret);
1102}
1103
1104/**
1105 * xmlOutputBufferCreateFd:
1106 * @fd: a file descriptor number
1107 * @encoder: the encoding converter or NULL
1108 *
1109 * Create a buffered output for the progressive saving
1110 * to a file descriptor
1111 *
1112 * Returns the new parser output or NULL
1113 */
1114xmlOutputBufferPtr
1115xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1116 xmlOutputBufferPtr ret;
1117
1118 if (fd < 0) return(NULL);
1119
1120 ret = xmlAllocOutputBuffer(encoder);
1121 if (ret != NULL) {
1122 ret->context = (void *) fd;
1123 ret->writecallback = xmlFdWrite;
1124 ret->closecallback = xmlFdClose;
1125 }
1126
1127 return(ret);
1128}
1129
1130/**
1131 * xmlParserInputBufferCreateIO:
1132 * @ioread: an I/O read function
1133 * @ioclose: an I/O close function
1134 * @ioctx: an I/O handler
1135 * @enc: the charset encoding if known
1136 *
1137 * Create a buffered parser input for the progressive parsing for the input
1138 * from an I/O handler
1139 *
1140 * Returns the new parser input or NULL
1141 */
1142xmlParserInputBufferPtr
1143xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1144 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1145 xmlParserInputBufferPtr ret;
1146
1147 if (ioread == NULL) return(NULL);
1148
1149 ret = xmlAllocParserInputBuffer(enc);
1150 if (ret != NULL) {
1151 ret->context = (void *) ioctx;
1152 ret->readcallback = ioread;
1153 ret->closecallback = ioclose;
1154 }
1155
1156 return(ret);
1157}
1158
1159/**
1160 * xmlOutputBufferCreateIO:
1161 * @iowrite: an I/O write function
1162 * @ioclose: an I/O close function
1163 * @ioctx: an I/O handler
1164 * @enc: the charset encoding if known
1165 *
1166 * Create a buffered output for the progressive saving
1167 * to an I/O handler
1168 *
1169 * Returns the new parser output or NULL
1170 */
1171xmlOutputBufferPtr
1172xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1173 xmlOutputCloseCallback ioclose, void *ioctx,
1174 xmlCharEncodingHandlerPtr encoder) {
1175 xmlOutputBufferPtr ret;
1176
1177 if (iowrite == NULL) return(NULL);
1178
1179 ret = xmlAllocOutputBuffer(encoder);
1180 if (ret != NULL) {
1181 ret->context = (void *) ioctx;
1182 ret->writecallback = iowrite;
1183 ret->closecallback = ioclose;
1184 }
1185
1186 return(ret);
1187}
1188
1189/**
1190 * xmlParserInputBufferPush:
1191 * @in: a buffered parser input
1192 * @len: the size in bytes of the array.
1193 * @buf: an char array
1194 *
1195 * Push the content of the arry in the input buffer
1196 * This routine handle the I18N transcoding to internal UTF-8
1197 * This is used when operating the parser in progressive (push) mode.
1198 *
1199 * Returns the number of chars read and stored in the buffer, or -1
1200 * in case of error.
1201 */
1202int
1203xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1204 int len, const char *buf) {
1205 int nbchars = 0;
1206
1207 if (len < 0) return(0);
1208 if (in->encoder != NULL) {
1209 /*
1210 * Store the data in the incoming raw buffer
1211 */
1212 if (in->raw == NULL) {
1213 in->raw = xmlBufferCreate();
1214 }
1215 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1216
1217 /*
1218 * convert as much as possible to the parser reading buffer.
1219 */
1220 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1221 if (nbchars < 0) {
1222 xmlGenericError(xmlGenericErrorContext,
1223 "xmlParserInputBufferPush: encoder error\n");
1224 return(-1);
1225 }
1226 } else {
1227 nbchars = len;
1228 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1229 }
1230#ifdef DEBUG_INPUT
1231 xmlGenericError(xmlGenericErrorContext,
1232 "I/O: pushed %d chars, buffer %d/%d\n",
1233 nbchars, in->buffer->use, in->buffer->size);
1234#endif
1235 return(nbchars);
1236}
1237
1238/**
1239 * xmlParserInputBufferGrow:
1240 * @in: a buffered parser input
1241 * @len: indicative value of the amount of chars to read
1242 *
1243 * Grow up the content of the input buffer, the old data are preserved
1244 * This routine handle the I18N transcoding to internal UTF-8
1245 * This routine is used when operating the parser in normal (pull) mode
1246 *
1247 * TODO: one should be able to remove one extra copy by copying directy
1248 * onto in->buffer or in->raw
1249 *
1250 * Returns the number of chars read and stored in the buffer, or -1
1251 * in case of error.
1252 */
1253int
1254xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1255 char *buffer = NULL;
1256 int res = 0;
1257 int nbchars = 0;
1258 int buffree;
1259
1260 if ((len <= MINLEN) && (len != 4))
1261 len = MINLEN;
1262 buffree = in->buffer->size - in->buffer->use;
1263 if (buffree <= 0) {
1264 xmlGenericError(xmlGenericErrorContext,
1265 "xmlParserInputBufferGrow : buffer full !\n");
1266 return(0);
1267 }
1268 if (len > buffree)
1269 len = buffree;
1270
1271 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
1272 if (buffer == NULL) {
1273 xmlGenericError(xmlGenericErrorContext,
1274 "xmlParserInputBufferGrow : out of memory !\n");
1275 return(-1);
1276 }
1277
1278 /*
1279 * Call the read method for this I/O type.
1280 */
1281 if (in->readcallback != NULL) {
1282 res = in->readcallback(in->context, &buffer[0], len);
1283 } else {
1284 xmlGenericError(xmlGenericErrorContext,
1285 "xmlParserInputBufferGrow : no input !\n");
1286 xmlFree(buffer);
1287 return(-1);
1288 }
1289 if (res < 0) {
1290 perror ("read error");
1291 xmlFree(buffer);
1292 return(-1);
1293 }
1294 len = res;
1295 if (in->encoder != NULL) {
1296 /*
1297 * Store the data in the incoming raw buffer
1298 */
1299 if (in->raw == NULL) {
1300 in->raw = xmlBufferCreate();
1301 }
1302 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
1303
1304 /*
1305 * convert as much as possible to the parser reading buffer.
1306 */
1307 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1308 if (nbchars < 0) {
1309 xmlGenericError(xmlGenericErrorContext,
1310 "xmlParserInputBufferGrow: encoder error\n");
1311 return(-1);
1312 }
1313 } else {
1314 nbchars = len;
1315 buffer[nbchars] = 0;
1316 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
1317 }
1318#ifdef DEBUG_INPUT
1319 xmlGenericError(xmlGenericErrorContext,
1320 "I/O: read %d chars, buffer %d/%d\n",
1321 nbchars, in->buffer->use, in->buffer->size);
1322#endif
1323 xmlFree(buffer);
1324 return(nbchars);
1325}
1326
1327/**
1328 * xmlParserInputBufferRead:
1329 * @in: a buffered parser input
1330 * @len: indicative value of the amount of chars to read
1331 *
1332 * Refresh the content of the input buffer, the old data are considered
1333 * consumed
1334 * This routine handle the I18N transcoding to internal UTF-8
1335 *
1336 * Returns the number of chars read and stored in the buffer, or -1
1337 * in case of error.
1338 */
1339int
1340xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1341 /* xmlBufferEmpty(in->buffer); */
1342 if (in->readcallback != NULL)
1343 return(xmlParserInputBufferGrow(in, len));
1344 else
1345 return(-1);
1346}
1347
1348/**
1349 * xmlOutputBufferWrite:
1350 * @out: a buffered parser output
1351 * @len: the size in bytes of the array.
1352 * @buf: an char array
1353 *
1354 * Write the content of the array in the output I/O buffer
1355 * This routine handle the I18N transcoding from internal UTF-8
1356 * The buffer is lossless, i.e. will store in case of partial
1357 * or delayed writes.
1358 *
1359 * Returns the number of chars immediately written, or -1
1360 * in case of error.
1361 */
1362int
1363xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
1364 int nbchars = 0; /* number of chars to output to I/O */
1365 int ret; /* return from function call */
1366 int written = 0; /* number of char written to I/O so far */
1367 int chunk; /* number of byte curreent processed from buf */
1368
1369 if (len < 0) return(0);
1370
1371 do {
1372 chunk = len;
1373 if (chunk > 4 * MINLEN)
1374 chunk = 4 * MINLEN;
1375
1376 /*
1377 * first handle encoding stuff.
1378 */
1379 if (out->encoder != NULL) {
1380 /*
1381 * Store the data in the incoming raw buffer
1382 */
1383 if (out->conv == NULL) {
1384 out->conv = xmlBufferCreate();
1385 }
1386 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
1387
1388 if ((out->buffer->use < MINLEN) && (chunk == len))
1389 goto done;
1390
1391 /*
1392 * convert as much as possible to the parser reading buffer.
1393 */
1394 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1395 if (ret < 0) {
1396 xmlGenericError(xmlGenericErrorContext,
1397 "xmlOutputBufferWrite: encoder error\n");
1398 return(-1);
1399 }
1400 nbchars = out->conv->use;
1401 } else {
1402 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
1403 nbchars = out->buffer->use;
1404 }
1405 buf += chunk;
1406 len -= chunk;
1407
1408 if ((nbchars < MINLEN) && (len <= 0))
1409 goto done;
1410
1411 if (out->writecallback) {
1412 /*
1413 * second write the stuff to the I/O channel
1414 */
1415 if (out->encoder != NULL) {
1416 ret = out->writecallback(out->context,
1417 (const char *)out->conv->content, nbchars);
1418 if (ret >= 0)
1419 xmlBufferShrink(out->conv, nbchars);
1420 } else {
1421 ret = out->writecallback(out->context,
1422 (const char *)out->buffer->content, nbchars);
1423 if (ret >= 0)
1424 xmlBufferShrink(out->buffer, nbchars);
1425 }
1426 if (ret < 0) {
1427 xmlGenericError(xmlGenericErrorContext,
1428 "I/O: error %d writing %d bytes\n", ret, nbchars);
1429 return(ret);
1430 }
1431 out->written += ret;
1432 }
1433 written += nbchars;
1434 } while (len > 0);
1435
1436done:
1437#ifdef DEBUG_INPUT
1438 xmlGenericError(xmlGenericErrorContext,
1439 "I/O: wrote %d chars\n", written);
1440#endif
1441 return(written);
1442}
1443
1444/**
1445 * xmlOutputBufferWriteString:
1446 * @out: a buffered parser output
1447 * @str: a zero terminated C string
1448 *
1449 * Write the content of the string in the output I/O buffer
1450 * This routine handle the I18N transcoding from internal UTF-8
1451 * The buffer is lossless, i.e. will store in case of partial
1452 * or delayed writes.
1453 *
1454 * Returns the number of chars immediately written, or -1
1455 * in case of error.
1456 */
1457int
1458xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
1459 int len;
1460
1461 if (str == NULL)
1462 return(-1);
1463 len = strlen(str);
1464
1465 if (len > 0)
1466 return(xmlOutputBufferWrite(out, len, str));
1467 return(len);
1468}
1469
1470/**
1471 * xmlOutputBufferFlush:
1472 * @out: a buffered output
1473 *
1474 * flushes the output I/O channel
1475 *
1476 * Returns the number of byte written or -1 in case of error.
1477 */
1478int
1479xmlOutputBufferFlush(xmlOutputBufferPtr out) {
1480 int nbchars = 0, ret = 0;
1481
1482 /*
1483 * first handle encoding stuff.
1484 */
1485 if ((out->conv != NULL) && (out->encoder != NULL)) {
1486 /*
1487 * convert as much as possible to the parser reading buffer.
1488 */
1489 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1490 if (nbchars < 0) {
1491 xmlGenericError(xmlGenericErrorContext,
1492 "xmlOutputBufferWrite: encoder error\n");
1493 return(-1);
1494 }
1495 }
1496
1497 /*
1498 * second flush the stuff to the I/O channel
1499 */
1500 if ((out->conv != NULL) && (out->encoder != NULL) &&
1501 (out->writecallback != NULL)) {
1502 ret = out->writecallback(out->context,
1503 (const char *)out->conv->content, out->conv->use);
1504 if (ret >= 0)
1505 xmlBufferShrink(out->conv, ret);
1506 } else if (out->writecallback != NULL) {
1507 ret = out->writecallback(out->context,
1508 (const char *)out->buffer->content, out->buffer->use);
1509 if (ret >= 0)
1510 xmlBufferShrink(out->buffer, ret);
1511 }
1512 if (ret < 0) {
1513 xmlGenericError(xmlGenericErrorContext,
1514 "I/O: error %d flushing %d bytes\n", ret, nbchars);
1515 return(ret);
1516 }
1517 out->written += ret;
1518
1519#ifdef DEBUG_INPUT
1520 xmlGenericError(xmlGenericErrorContext,
1521 "I/O: flushed %d chars\n", ret);
1522#endif
1523 return(ret);
1524}
1525
1526/*
1527 * xmlParserGetDirectory:
1528 * @filename: the path to a file
1529 *
1530 * lookup the directory for that file
1531 *
1532 * Returns a new allocated string containing the directory, or NULL.
1533 */
1534char *
1535xmlParserGetDirectory(const char *filename) {
1536 char *ret = NULL;
1537 char dir[1024];
1538 char *cur;
1539 char sep = '/';
1540
1541 if (xmlInputCallbackInitialized == 0)
1542 xmlRegisterDefaultInputCallbacks();
1543
1544 if (filename == NULL) return(NULL);
1545#ifdef WIN32
1546 sep = '\\';
1547#endif
1548
1549 strncpy(dir, filename, 1023);
1550 dir[1023] = 0;
1551 cur = &dir[strlen(dir)];
1552 while (cur > dir) {
1553 if (*cur == sep) break;
1554 cur --;
1555 }
1556 if (*cur == sep) {
1557 if (cur == dir) dir[1] = 0;
1558 else *cur = 0;
1559 ret = xmlMemStrdup(dir);
1560 } else {
1561 if (getcwd(dir, 1024) != NULL) {
1562 dir[1023] = 0;
1563 ret = xmlMemStrdup(dir);
1564 }
1565 }
1566 return(ret);
1567}
1568
1569/****************************************************************
1570 * *
1571 * External entities loading *
1572 * *
1573 ****************************************************************/
1574
1575/*
1576 * xmlDefaultExternalEntityLoader:
1577 * @URL: the URL for the entity to load
1578 * @ID: the System ID for the entity to load
1579 * @ctxt: the context in which the entity is called or NULL
1580 *
1581 * By default we don't load external entitites, yet.
1582 *
1583 * Returns a new allocated xmlParserInputPtr, or NULL.
1584 */
1585static
1586xmlParserInputPtr
1587xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
1588 xmlParserCtxtPtr ctxt) {
1589 xmlParserInputPtr ret = NULL;
1590
1591#ifdef DEBUG_EXTERNAL_ENTITIES
1592 xmlGenericError(xmlGenericErrorContext,
1593 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
1594#endif
1595 if (URL == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00001596 if ((ctxt->validate) && (ctxt->sax != NULL) &&
1597 (ctxt->sax->error != NULL))
1598 ctxt->sax->error(ctxt,
1599 "failed to load external entity \"%s\"\n", ID);
1600 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001601 ctxt->sax->warning(ctxt,
1602 "failed to load external entity \"%s\"\n", ID);
1603 return(NULL);
1604 }
1605 ret = xmlNewInputFromFile(ctxt, URL);
1606 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00001607 if ((ctxt->validate) && (ctxt->sax != NULL) &&
1608 (ctxt->sax->error != NULL))
1609 ctxt->sax->error(ctxt,
1610 "failed to load external entity \"%s\"\n", URL);
1611 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001612 ctxt->sax->warning(ctxt,
1613 "failed to load external entity \"%s\"\n", URL);
1614 }
1615 return(ret);
1616}
1617
1618static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1619 xmlDefaultExternalEntityLoader;
1620
1621/*
1622 * xmlSetExternalEntityLoader:
1623 * @f: the new entity resolver function
1624 *
1625 * Changes the defaultexternal entity resolver function for the application
1626 */
1627void
1628xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1629 xmlCurrentExternalEntityLoader = f;
1630}
1631
1632/*
1633 * xmlGetExternalEntityLoader:
1634 *
1635 * Get the default external entity resolver function for the application
1636 *
1637 * Returns the xmlExternalEntityLoader function pointer
1638 */
1639xmlExternalEntityLoader
1640xmlGetExternalEntityLoader(void) {
1641 return(xmlCurrentExternalEntityLoader);
1642}
1643
1644/*
1645 * xmlLoadExternalEntity:
1646 * @URL: the URL for the entity to load
1647 * @ID: the System ID for the entity to load
1648 * @ctxt: the context in which the entity is called or NULL
1649 *
1650 * Load an external entity, note that the use of this function for
1651 * unparsed entities may generate problems
1652 * TODO: a more generic External entitiy API must be designed
1653 *
1654 * Returns the xmlParserInputPtr or NULL
1655 */
1656xmlParserInputPtr
1657xmlLoadExternalEntity(const char *URL, const char *ID,
1658 xmlParserCtxtPtr ctxt) {
1659 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
1660}
1661