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