blob: 9560fb8755e439272581c7404c6b6f28b16779bf [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
Owen Taylor3473f882001-02-23 17:55:21 +0000828 xmlFree(in);
829}
830
831/**
832 * xmlOutputBufferClose:
833 * @out: a buffered output
834 *
835 * flushes and close the output I/O channel
836 * and free up all the associated resources
837 *
838 * Returns the number of byte written or -1 in case of error.
839 */
840int
841xmlOutputBufferClose(xmlOutputBufferPtr out) {
842 int written;
843
844 if (out == NULL)
845 return(-1);
846 if (out->writecallback != NULL)
847 xmlOutputBufferFlush(out);
848 if (out->closecallback != NULL) {
849 out->closecallback(out->context);
850 }
851 written = out->written;
852 if (out->conv) {
853 xmlBufferFree(out->conv);
854 out->conv = NULL;
855 }
856 if (out->encoder != NULL) {
857 xmlCharEncCloseFunc(out->encoder);
858 }
859 if (out->buffer != NULL) {
860 xmlBufferFree(out->buffer);
861 out->buffer = NULL;
862 }
863
Owen Taylor3473f882001-02-23 17:55:21 +0000864 xmlFree(out);
865 return(written);
866}
867
868/**
869 * xmlParserInputBufferCreateFilename:
870 * @URI: a C string containing the URI or filename
871 * @enc: the charset encoding if known
872 *
873 * Create a buffered parser input for the progressive parsing of a file
874 * If filename is "-' then we use stdin as the input.
875 * Automatic support for ZLIB/Compress compressed document is provided
876 * by default if found at compile-time.
877 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
878 *
879 * Returns the new parser input or NULL
880 */
881xmlParserInputBufferPtr
882#ifdef VMS
883xmlParserInputBufferCreateFname
884#else
885xmlParserInputBufferCreateFilename
886#endif
887(const char *URI, xmlCharEncoding enc) {
888 xmlParserInputBufferPtr ret;
889 int i;
890 void *context = NULL;
891
892 if (xmlInputCallbackInitialized == 0)
893 xmlRegisterDefaultInputCallbacks();
894
895 if (URI == NULL) return(NULL);
896
897 /*
898 * Try to find one of the input accept method accepting taht scheme
899 * Go in reverse to give precedence to user defined handlers.
900 */
901 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
902 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
903 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
904 context = xmlInputCallbackTable[i].opencallback(URI);
905 if (context != NULL)
906 break;
907 }
908 }
909 if (context == NULL) {
910 return(NULL);
911 }
912
913 /*
914 * Allocate the Input buffer front-end.
915 */
916 ret = xmlAllocParserInputBuffer(enc);
917 if (ret != NULL) {
918 ret->context = context;
919 ret->readcallback = xmlInputCallbackTable[i].readcallback;
920 ret->closecallback = xmlInputCallbackTable[i].closecallback;
921 }
922 return(ret);
923}
924
925/**
926 * xmlOutputBufferCreateFilename:
927 * @URI: a C string containing the URI or filename
928 * @encoder: the encoding converter or NULL
929 * @compression: the compression ration (0 none, 9 max).
930 *
931 * Create a buffered output for the progressive saving of a file
932 * If filename is "-' then we use stdout as the output.
933 * Automatic support for ZLIB/Compress compressed document is provided
934 * by default if found at compile-time.
935 * TODO: currently if compression is set, the library only support
936 * writing to a local file.
937 *
938 * Returns the new output or NULL
939 */
940xmlOutputBufferPtr
941xmlOutputBufferCreateFilename(const char *URI,
942 xmlCharEncodingHandlerPtr encoder,
943 int compression) {
944 xmlOutputBufferPtr ret;
945 int i;
946 void *context = NULL;
947
948 if (xmlOutputCallbackInitialized == 0)
949 xmlRegisterDefaultOutputCallbacks();
950
951 if (URI == NULL) return(NULL);
952
953#ifdef HAVE_ZLIB_H
954 if ((compression > 0) && (compression <= 9)) {
955 context = xmlGzfileOpenW(URI, compression);
956 if (context != NULL) {
957 ret = xmlAllocOutputBuffer(encoder);
958 if (ret != NULL) {
959 ret->context = context;
960 ret->writecallback = xmlGzfileWrite;
961 ret->closecallback = xmlGzfileClose;
962 }
963 return(ret);
964 }
965 }
966#endif
967
968 /*
969 * Try to find one of the output accept method accepting taht scheme
970 * Go in reverse to give precedence to user defined handlers.
971 */
972 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
973 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
974 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
975 context = xmlOutputCallbackTable[i].opencallback(URI);
976 if (context != NULL)
977 break;
978 }
979 }
980 if (context == NULL) {
981 return(NULL);
982 }
983
984 /*
985 * Allocate the Output buffer front-end.
986 */
987 ret = xmlAllocOutputBuffer(encoder);
988 if (ret != NULL) {
989 ret->context = context;
990 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
991 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
992 }
993 return(ret);
994}
995
996/**
997 * xmlParserInputBufferCreateFile:
998 * @file: a FILE*
999 * @enc: the charset encoding if known
1000 *
1001 * Create a buffered parser input for the progressive parsing of a FILE *
1002 * buffered C I/O
1003 *
1004 * Returns the new parser input or NULL
1005 */
1006xmlParserInputBufferPtr
1007xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1008 xmlParserInputBufferPtr ret;
1009
1010 if (xmlInputCallbackInitialized == 0)
1011 xmlRegisterDefaultInputCallbacks();
1012
1013 if (file == NULL) return(NULL);
1014
1015 ret = xmlAllocParserInputBuffer(enc);
1016 if (ret != NULL) {
1017 ret->context = file;
1018 ret->readcallback = xmlFileRead;
1019 ret->closecallback = xmlFileFlush;
1020 }
1021
1022 return(ret);
1023}
1024
1025/**
1026 * xmlOutputBufferCreateFile:
1027 * @file: a FILE*
1028 * @encoder: the encoding converter or NULL
1029 *
1030 * Create a buffered output for the progressive saving to a FILE *
1031 * buffered C I/O
1032 *
1033 * Returns the new parser output or NULL
1034 */
1035xmlOutputBufferPtr
1036xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1037 xmlOutputBufferPtr ret;
1038
1039 if (xmlOutputCallbackInitialized == 0)
1040 xmlRegisterDefaultOutputCallbacks();
1041
1042 if (file == NULL) return(NULL);
1043
1044 ret = xmlAllocOutputBuffer(encoder);
1045 if (ret != NULL) {
1046 ret->context = file;
1047 ret->writecallback = xmlFileWrite;
1048 ret->closecallback = xmlFileFlush;
1049 }
1050
1051 return(ret);
1052}
1053
1054/**
1055 * xmlParserInputBufferCreateFd:
1056 * @fd: a file descriptor number
1057 * @enc: the charset encoding if known
1058 *
1059 * Create a buffered parser input for the progressive parsing for the input
1060 * from a file descriptor
1061 *
1062 * Returns the new parser input or NULL
1063 */
1064xmlParserInputBufferPtr
1065xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1066 xmlParserInputBufferPtr ret;
1067
1068 if (fd < 0) return(NULL);
1069
1070 ret = xmlAllocParserInputBuffer(enc);
1071 if (ret != NULL) {
1072 ret->context = (void *) fd;
1073 ret->readcallback = xmlFdRead;
1074 ret->closecallback = xmlFdClose;
1075 }
1076
1077 return(ret);
1078}
1079
1080/**
1081 * xmlParserInputBufferCreateMem:
1082 * @mem: the memory input
1083 * @size: the length of the memory block
1084 * @enc: the charset encoding if known
1085 *
1086 * Create a buffered parser input for the progressive parsing for the input
1087 * from a memory area.
1088 *
1089 * Returns the new parser input or NULL
1090 */
1091xmlParserInputBufferPtr
1092xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1093 xmlParserInputBufferPtr ret;
1094
1095 if (size <= 0) return(NULL);
1096 if (mem == NULL) return(NULL);
1097
1098 ret = xmlAllocParserInputBuffer(enc);
1099 if (ret != NULL) {
1100 ret->context = (void *) mem;
1101 ret->readcallback = (xmlInputReadCallback) xmlNop;
1102 ret->closecallback = NULL;
1103 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1104 }
1105
1106 return(ret);
1107}
1108
1109/**
1110 * xmlOutputBufferCreateFd:
1111 * @fd: a file descriptor number
1112 * @encoder: the encoding converter or NULL
1113 *
1114 * Create a buffered output for the progressive saving
1115 * to a file descriptor
1116 *
1117 * Returns the new parser output or NULL
1118 */
1119xmlOutputBufferPtr
1120xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1121 xmlOutputBufferPtr ret;
1122
1123 if (fd < 0) return(NULL);
1124
1125 ret = xmlAllocOutputBuffer(encoder);
1126 if (ret != NULL) {
1127 ret->context = (void *) fd;
1128 ret->writecallback = xmlFdWrite;
1129 ret->closecallback = xmlFdClose;
1130 }
1131
1132 return(ret);
1133}
1134
1135/**
1136 * xmlParserInputBufferCreateIO:
1137 * @ioread: an I/O read function
1138 * @ioclose: an I/O close function
1139 * @ioctx: an I/O handler
1140 * @enc: the charset encoding if known
1141 *
1142 * Create a buffered parser input for the progressive parsing for the input
1143 * from an I/O handler
1144 *
1145 * Returns the new parser input or NULL
1146 */
1147xmlParserInputBufferPtr
1148xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1149 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1150 xmlParserInputBufferPtr ret;
1151
1152 if (ioread == NULL) return(NULL);
1153
1154 ret = xmlAllocParserInputBuffer(enc);
1155 if (ret != NULL) {
1156 ret->context = (void *) ioctx;
1157 ret->readcallback = ioread;
1158 ret->closecallback = ioclose;
1159 }
1160
1161 return(ret);
1162}
1163
1164/**
1165 * xmlOutputBufferCreateIO:
1166 * @iowrite: an I/O write function
1167 * @ioclose: an I/O close function
1168 * @ioctx: an I/O handler
1169 * @enc: the charset encoding if known
1170 *
1171 * Create a buffered output for the progressive saving
1172 * to an I/O handler
1173 *
1174 * Returns the new parser output or NULL
1175 */
1176xmlOutputBufferPtr
1177xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1178 xmlOutputCloseCallback ioclose, void *ioctx,
1179 xmlCharEncodingHandlerPtr encoder) {
1180 xmlOutputBufferPtr ret;
1181
1182 if (iowrite == NULL) return(NULL);
1183
1184 ret = xmlAllocOutputBuffer(encoder);
1185 if (ret != NULL) {
1186 ret->context = (void *) ioctx;
1187 ret->writecallback = iowrite;
1188 ret->closecallback = ioclose;
1189 }
1190
1191 return(ret);
1192}
1193
1194/**
1195 * xmlParserInputBufferPush:
1196 * @in: a buffered parser input
1197 * @len: the size in bytes of the array.
1198 * @buf: an char array
1199 *
1200 * Push the content of the arry in the input buffer
1201 * This routine handle the I18N transcoding to internal UTF-8
1202 * This is used when operating the parser in progressive (push) mode.
1203 *
1204 * Returns the number of chars read and stored in the buffer, or -1
1205 * in case of error.
1206 */
1207int
1208xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1209 int len, const char *buf) {
1210 int nbchars = 0;
1211
1212 if (len < 0) return(0);
1213 if (in->encoder != NULL) {
1214 /*
1215 * Store the data in the incoming raw buffer
1216 */
1217 if (in->raw == NULL) {
1218 in->raw = xmlBufferCreate();
1219 }
1220 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1221
1222 /*
1223 * convert as much as possible to the parser reading buffer.
1224 */
1225 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1226 if (nbchars < 0) {
1227 xmlGenericError(xmlGenericErrorContext,
1228 "xmlParserInputBufferPush: encoder error\n");
1229 return(-1);
1230 }
1231 } else {
1232 nbchars = len;
1233 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1234 }
1235#ifdef DEBUG_INPUT
1236 xmlGenericError(xmlGenericErrorContext,
1237 "I/O: pushed %d chars, buffer %d/%d\n",
1238 nbchars, in->buffer->use, in->buffer->size);
1239#endif
1240 return(nbchars);
1241}
1242
1243/**
1244 * xmlParserInputBufferGrow:
1245 * @in: a buffered parser input
1246 * @len: indicative value of the amount of chars to read
1247 *
1248 * Grow up the content of the input buffer, the old data are preserved
1249 * This routine handle the I18N transcoding to internal UTF-8
1250 * This routine is used when operating the parser in normal (pull) mode
1251 *
1252 * TODO: one should be able to remove one extra copy by copying directy
1253 * onto in->buffer or in->raw
1254 *
1255 * Returns the number of chars read and stored in the buffer, or -1
1256 * in case of error.
1257 */
1258int
1259xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1260 char *buffer = NULL;
1261 int res = 0;
1262 int nbchars = 0;
1263 int buffree;
1264
1265 if ((len <= MINLEN) && (len != 4))
1266 len = MINLEN;
1267 buffree = in->buffer->size - in->buffer->use;
1268 if (buffree <= 0) {
1269 xmlGenericError(xmlGenericErrorContext,
1270 "xmlParserInputBufferGrow : buffer full !\n");
1271 return(0);
1272 }
1273 if (len > buffree)
1274 len = buffree;
1275
1276 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
1277 if (buffer == NULL) {
1278 xmlGenericError(xmlGenericErrorContext,
1279 "xmlParserInputBufferGrow : out of memory !\n");
1280 return(-1);
1281 }
1282
1283 /*
1284 * Call the read method for this I/O type.
1285 */
1286 if (in->readcallback != NULL) {
1287 res = in->readcallback(in->context, &buffer[0], len);
1288 } else {
1289 xmlGenericError(xmlGenericErrorContext,
1290 "xmlParserInputBufferGrow : no input !\n");
1291 xmlFree(buffer);
1292 return(-1);
1293 }
1294 if (res < 0) {
1295 perror ("read error");
1296 xmlFree(buffer);
1297 return(-1);
1298 }
1299 len = res;
1300 if (in->encoder != NULL) {
1301 /*
1302 * Store the data in the incoming raw buffer
1303 */
1304 if (in->raw == NULL) {
1305 in->raw = xmlBufferCreate();
1306 }
1307 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
1308
1309 /*
1310 * convert as much as possible to the parser reading buffer.
1311 */
1312 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1313 if (nbchars < 0) {
1314 xmlGenericError(xmlGenericErrorContext,
1315 "xmlParserInputBufferGrow: encoder error\n");
1316 return(-1);
1317 }
1318 } else {
1319 nbchars = len;
1320 buffer[nbchars] = 0;
1321 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
1322 }
1323#ifdef DEBUG_INPUT
1324 xmlGenericError(xmlGenericErrorContext,
1325 "I/O: read %d chars, buffer %d/%d\n",
1326 nbchars, in->buffer->use, in->buffer->size);
1327#endif
1328 xmlFree(buffer);
1329 return(nbchars);
1330}
1331
1332/**
1333 * xmlParserInputBufferRead:
1334 * @in: a buffered parser input
1335 * @len: indicative value of the amount of chars to read
1336 *
1337 * Refresh the content of the input buffer, the old data are considered
1338 * consumed
1339 * This routine handle the I18N transcoding to internal UTF-8
1340 *
1341 * Returns the number of chars read and stored in the buffer, or -1
1342 * in case of error.
1343 */
1344int
1345xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1346 /* xmlBufferEmpty(in->buffer); */
1347 if (in->readcallback != NULL)
1348 return(xmlParserInputBufferGrow(in, len));
1349 else
1350 return(-1);
1351}
1352
1353/**
1354 * xmlOutputBufferWrite:
1355 * @out: a buffered parser output
1356 * @len: the size in bytes of the array.
1357 * @buf: an char array
1358 *
1359 * Write the content of the array in the output I/O buffer
1360 * This routine handle the I18N transcoding from internal UTF-8
1361 * The buffer is lossless, i.e. will store in case of partial
1362 * or delayed writes.
1363 *
1364 * Returns the number of chars immediately written, or -1
1365 * in case of error.
1366 */
1367int
1368xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
1369 int nbchars = 0; /* number of chars to output to I/O */
1370 int ret; /* return from function call */
1371 int written = 0; /* number of char written to I/O so far */
1372 int chunk; /* number of byte curreent processed from buf */
1373
1374 if (len < 0) return(0);
1375
1376 do {
1377 chunk = len;
1378 if (chunk > 4 * MINLEN)
1379 chunk = 4 * MINLEN;
1380
1381 /*
1382 * first handle encoding stuff.
1383 */
1384 if (out->encoder != NULL) {
1385 /*
1386 * Store the data in the incoming raw buffer
1387 */
1388 if (out->conv == NULL) {
1389 out->conv = xmlBufferCreate();
1390 }
1391 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
1392
1393 if ((out->buffer->use < MINLEN) && (chunk == len))
1394 goto done;
1395
1396 /*
1397 * convert as much as possible to the parser reading buffer.
1398 */
1399 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1400 if (ret < 0) {
1401 xmlGenericError(xmlGenericErrorContext,
1402 "xmlOutputBufferWrite: encoder error\n");
1403 return(-1);
1404 }
1405 nbchars = out->conv->use;
1406 } else {
1407 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
1408 nbchars = out->buffer->use;
1409 }
1410 buf += chunk;
1411 len -= chunk;
1412
1413 if ((nbchars < MINLEN) && (len <= 0))
1414 goto done;
1415
1416 if (out->writecallback) {
1417 /*
1418 * second write the stuff to the I/O channel
1419 */
1420 if (out->encoder != NULL) {
1421 ret = out->writecallback(out->context,
1422 (const char *)out->conv->content, nbchars);
1423 if (ret >= 0)
1424 xmlBufferShrink(out->conv, nbchars);
1425 } else {
1426 ret = out->writecallback(out->context,
1427 (const char *)out->buffer->content, nbchars);
1428 if (ret >= 0)
1429 xmlBufferShrink(out->buffer, nbchars);
1430 }
1431 if (ret < 0) {
1432 xmlGenericError(xmlGenericErrorContext,
1433 "I/O: error %d writing %d bytes\n", ret, nbchars);
1434 return(ret);
1435 }
1436 out->written += ret;
1437 }
1438 written += nbchars;
1439 } while (len > 0);
1440
1441done:
1442#ifdef DEBUG_INPUT
1443 xmlGenericError(xmlGenericErrorContext,
1444 "I/O: wrote %d chars\n", written);
1445#endif
1446 return(written);
1447}
1448
1449/**
1450 * xmlOutputBufferWriteString:
1451 * @out: a buffered parser output
1452 * @str: a zero terminated C string
1453 *
1454 * Write the content of the string in the output I/O buffer
1455 * This routine handle the I18N transcoding from internal UTF-8
1456 * The buffer is lossless, i.e. will store in case of partial
1457 * or delayed writes.
1458 *
1459 * Returns the number of chars immediately written, or -1
1460 * in case of error.
1461 */
1462int
1463xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
1464 int len;
1465
1466 if (str == NULL)
1467 return(-1);
1468 len = strlen(str);
1469
1470 if (len > 0)
1471 return(xmlOutputBufferWrite(out, len, str));
1472 return(len);
1473}
1474
1475/**
1476 * xmlOutputBufferFlush:
1477 * @out: a buffered output
1478 *
1479 * flushes the output I/O channel
1480 *
1481 * Returns the number of byte written or -1 in case of error.
1482 */
1483int
1484xmlOutputBufferFlush(xmlOutputBufferPtr out) {
1485 int nbchars = 0, ret = 0;
1486
1487 /*
1488 * first handle encoding stuff.
1489 */
1490 if ((out->conv != NULL) && (out->encoder != NULL)) {
1491 /*
1492 * convert as much as possible to the parser reading buffer.
1493 */
1494 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1495 if (nbchars < 0) {
1496 xmlGenericError(xmlGenericErrorContext,
1497 "xmlOutputBufferWrite: encoder error\n");
1498 return(-1);
1499 }
1500 }
1501
1502 /*
1503 * second flush the stuff to the I/O channel
1504 */
1505 if ((out->conv != NULL) && (out->encoder != NULL) &&
1506 (out->writecallback != NULL)) {
1507 ret = out->writecallback(out->context,
1508 (const char *)out->conv->content, out->conv->use);
1509 if (ret >= 0)
1510 xmlBufferShrink(out->conv, ret);
1511 } else if (out->writecallback != NULL) {
1512 ret = out->writecallback(out->context,
1513 (const char *)out->buffer->content, out->buffer->use);
1514 if (ret >= 0)
1515 xmlBufferShrink(out->buffer, ret);
1516 }
1517 if (ret < 0) {
1518 xmlGenericError(xmlGenericErrorContext,
1519 "I/O: error %d flushing %d bytes\n", ret, nbchars);
1520 return(ret);
1521 }
1522 out->written += ret;
1523
1524#ifdef DEBUG_INPUT
1525 xmlGenericError(xmlGenericErrorContext,
1526 "I/O: flushed %d chars\n", ret);
1527#endif
1528 return(ret);
1529}
1530
1531/*
1532 * xmlParserGetDirectory:
1533 * @filename: the path to a file
1534 *
1535 * lookup the directory for that file
1536 *
1537 * Returns a new allocated string containing the directory, or NULL.
1538 */
1539char *
1540xmlParserGetDirectory(const char *filename) {
1541 char *ret = NULL;
1542 char dir[1024];
1543 char *cur;
1544 char sep = '/';
1545
1546 if (xmlInputCallbackInitialized == 0)
1547 xmlRegisterDefaultInputCallbacks();
1548
1549 if (filename == NULL) return(NULL);
1550#ifdef WIN32
1551 sep = '\\';
1552#endif
1553
1554 strncpy(dir, filename, 1023);
1555 dir[1023] = 0;
1556 cur = &dir[strlen(dir)];
1557 while (cur > dir) {
1558 if (*cur == sep) break;
1559 cur --;
1560 }
1561 if (*cur == sep) {
1562 if (cur == dir) dir[1] = 0;
1563 else *cur = 0;
1564 ret = xmlMemStrdup(dir);
1565 } else {
1566 if (getcwd(dir, 1024) != NULL) {
1567 dir[1023] = 0;
1568 ret = xmlMemStrdup(dir);
1569 }
1570 }
1571 return(ret);
1572}
1573
1574/****************************************************************
1575 * *
1576 * External entities loading *
1577 * *
1578 ****************************************************************/
1579
1580/*
1581 * xmlDefaultExternalEntityLoader:
1582 * @URL: the URL for the entity to load
1583 * @ID: the System ID for the entity to load
1584 * @ctxt: the context in which the entity is called or NULL
1585 *
1586 * By default we don't load external entitites, yet.
1587 *
1588 * Returns a new allocated xmlParserInputPtr, or NULL.
1589 */
1590static
1591xmlParserInputPtr
1592xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
1593 xmlParserCtxtPtr ctxt) {
1594 xmlParserInputPtr ret = NULL;
1595
1596#ifdef DEBUG_EXTERNAL_ENTITIES
1597 xmlGenericError(xmlGenericErrorContext,
1598 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
1599#endif
1600 if (URL == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00001601 if ((ctxt->validate) && (ctxt->sax != NULL) &&
1602 (ctxt->sax->error != NULL))
1603 ctxt->sax->error(ctxt,
1604 "failed to load external entity \"%s\"\n", ID);
1605 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001606 ctxt->sax->warning(ctxt,
1607 "failed to load external entity \"%s\"\n", ID);
1608 return(NULL);
1609 }
1610 ret = xmlNewInputFromFile(ctxt, URL);
1611 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00001612 if ((ctxt->validate) && (ctxt->sax != NULL) &&
1613 (ctxt->sax->error != NULL))
1614 ctxt->sax->error(ctxt,
1615 "failed to load external entity \"%s\"\n", URL);
1616 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00001617 ctxt->sax->warning(ctxt,
1618 "failed to load external entity \"%s\"\n", URL);
1619 }
1620 return(ret);
1621}
1622
1623static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1624 xmlDefaultExternalEntityLoader;
1625
1626/*
1627 * xmlSetExternalEntityLoader:
1628 * @f: the new entity resolver function
1629 *
1630 * Changes the defaultexternal entity resolver function for the application
1631 */
1632void
1633xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1634 xmlCurrentExternalEntityLoader = f;
1635}
1636
1637/*
1638 * xmlGetExternalEntityLoader:
1639 *
1640 * Get the default external entity resolver function for the application
1641 *
1642 * Returns the xmlExternalEntityLoader function pointer
1643 */
1644xmlExternalEntityLoader
1645xmlGetExternalEntityLoader(void) {
1646 return(xmlCurrentExternalEntityLoader);
1647}
1648
1649/*
1650 * xmlLoadExternalEntity:
1651 * @URL: the URL for the entity to load
1652 * @ID: the System ID for the entity to load
1653 * @ctxt: the context in which the entity is called or NULL
1654 *
1655 * Load an external entity, note that the use of this function for
1656 * unparsed entities may generate problems
1657 * TODO: a more generic External entitiy API must be designed
1658 *
1659 * Returns the xmlParserInputPtr or NULL
1660 */
1661xmlParserInputPtr
1662xmlLoadExternalEntity(const char *URL, const char *ID,
1663 xmlParserCtxtPtr ctxt) {
1664 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
1665}
1666