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