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