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