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