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