blob: fdf961c42a215d524fabba0681f81d404d93785f [file] [log] [blame]
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel.Veillard@w3.org
7 */
8
Daniel Veillard7f7d1111999-09-22 09:46:25 +00009#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000010#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000011#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +000012#include "config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000013#endif
Daniel Veillarde2d034d1999-07-27 19:52:06 +000014
Daniel Veillard7f7d1111999-09-22 09:46:25 +000015#include <stdio.h>
16#include <string.h>
17
18#ifdef HAVE_SYS_TYPES_H
Daniel Veillarde2d034d1999-07-27 19:52:06 +000019#include <sys/types.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000020#endif
21#ifdef HAVE_SYS_STAT_H
Daniel Veillarde2d034d1999-07-27 19:52:06 +000022#include <sys/stat.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000023#endif
24#ifdef HAVE_FCNTL_H
Daniel Veillarde2d034d1999-07-27 19:52:06 +000025#include <fcntl.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000026#endif
Daniel Veillarde2d034d1999-07-27 19:52:06 +000027#ifdef HAVE_UNISTD_H
28#include <unistd.h>
29#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000030#ifdef HAVE_STDLIB_H
31#include <stdlib.h>
32#endif
Daniel Veillarde2d034d1999-07-27 19:52:06 +000033#ifdef HAVE_ZLIB_H
34#include <zlib.h>
35#endif
36
Daniel Veillard361d8452000-04-03 19:48:13 +000037#include <libxml/xmlmemory.h>
38#include <libxml/parser.h>
39#include <libxml/parserInternals.h>
40#include <libxml/xmlIO.h>
41#include <libxml/nanohttp.h>
42#include <libxml/nanoftp.h>
Daniel Veillarde2d034d1999-07-27 19:52:06 +000043
Daniel Veillarde2d034d1999-07-27 19:52:06 +000044/* #define VERBOSE_FAILURE */
Daniel Veillardb96e6431999-08-29 21:02:19 +000045/* #define DEBUG_EXTERNAL_ENTITIES */
Daniel Veillardbe803962000-06-28 23:40:59 +000046/* #define DEBUG_INPUT */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000047
48#ifdef DEBUG_INPUT
49#define MINLEN 40
50#else
51#define MINLEN 4000
52#endif
53
Daniel Veillard5d211f42000-04-07 17:00:24 +000054/*
55 * Input I/O callback sets
56 */
57typedef struct _xmlInputCallback {
58 xmlInputMatchCallback matchcallback;
59 xmlInputOpenCallback opencallback;
60 xmlInputReadCallback readcallback;
61 xmlInputCloseCallback closecallback;
62} xmlInputCallback;
63
64#define MAX_INPUT_CALLBACK 15
65
66xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
67int xmlInputCallbackNr = 0;
68int xmlInputCallbackInitialized = 0;
69
Daniel Veillardbe803962000-06-28 23:40:59 +000070/*
71 * Output I/O callback sets
72 */
73typedef struct _xmlOutputCallback {
74 xmlOutputMatchCallback matchcallback;
75 xmlOutputOpenCallback opencallback;
76 xmlOutputWriteCallback writecallback;
77 xmlOutputCloseCallback closecallback;
78} xmlOutputCallback;
79
80#define MAX_OUTPUT_CALLBACK 15
81
82xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
83int xmlOutputCallbackNr = 0;
84int xmlOutputCallbackInitialized = 0;
85
Daniel Veillard5d211f42000-04-07 17:00:24 +000086/************************************************************************
87 * *
88 * Standard I/O for file accesses *
89 * *
90 ************************************************************************/
91
92/**
93 * xmlFdMatch:
94 * @filename: the URI for matching
95 *
96 * input from file descriptor
97 *
98 * Returns 1 if matches, 0 otherwise
99 */
100int
101xmlFdMatch (const char *filename) {
102 return(1);
103}
104
105/**
106 * xmlFdOpen:
107 * @filename: the URI for matching
108 *
109 * input from file descriptor, supports compressed input
110 * if @filename is " " then the standard input is used
111 *
112 * Returns an I/O context or NULL in case of error
113 */
114void *
115xmlFdOpen (const char *filename) {
116 const char *path = NULL;
117 int fd;
118
119 if (!strcmp(filename, "-")) {
120 fd = 0;
121 return((void *) fd);
122 }
123
124 if (!strncmp(filename, "file://localhost", 16))
125 path = &filename[16];
126 else if (!strncmp(filename, "file:///", 8))
127 path = &filename[8];
128 else if (filename[0] == '/')
129 path = filename;
130 if (path == NULL)
131 return(NULL);
132
133#ifdef WIN32
134 fd = _open (filename, O_RDONLY | _O_BINARY);
135#else
136 fd = open (filename, O_RDONLY);
137#endif
138
139 return((void *) fd);
140}
141
142/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000143 * xmlFdOpenW:
144 * @filename: the URI for matching
145 *
146 * input from file descriptor,
147 * if @filename is "-" then the standard output is used
148 *
149 * Returns an I/O context or NULL in case of error
150 */
151void *
152xmlFdOpenW (const char *filename) {
153 const char *path = NULL;
154 int fd;
155
156 if (!strcmp(filename, "-")) {
157 fd = 1;
158 return((void *) fd);
159 }
160
161 if (!strncmp(filename, "file://localhost", 16))
162 path = &filename[16];
163 else if (!strncmp(filename, "file:///", 8))
164 path = &filename[8];
165 else if (filename[0] == '/')
166 path = filename;
167 if (path == NULL)
168 return(NULL);
169
170 fd = open (filename, O_WRONLY);
171
172 return((void *) fd);
173}
174
175/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000176 * xmlFdRead:
177 * @context: the I/O context
178 * @buffer: where to drop data
Daniel Veillardbe803962000-06-28 23:40:59 +0000179 * @len: number of bytes to read
Daniel Veillard5d211f42000-04-07 17:00:24 +0000180 *
181 * Read @len bytes to @buffer from the I/O channel.
182 *
183 * Returns the number of bytes written
184 */
185int
186xmlFdRead (void * context, char * buffer, int len) {
187 return(read((int) context, &buffer[0], len));
188}
189
190/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000191 * xmlFdWrite:
192 * @context: the I/O context
193 * @buffer: where to get data
194 * @len: number of bytes to write
195 *
196 * Write @len bytes from @buffer to the I/O channel.
197 *
198 * Returns the number of bytes written
199 */
200int
201xmlFdWrite (void * context, const char * buffer, int len) {
202 return(write((int) context, &buffer[0], len));
203}
204
205/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000206 * xmlFdClose:
207 * @context: the I/O context
208 *
209 * Close an I/O channel
210 */
211void
212xmlFdClose (void * context) {
213 close((int) context);
214}
215
216/**
217 * xmlFileMatch:
218 * @filename: the URI for matching
219 *
220 * input from FILE *
221 *
222 * Returns 1 if matches, 0 otherwise
223 */
224int
225xmlFileMatch (const char *filename) {
226 return(1);
227}
228
229/**
230 * xmlFileOpen:
231 * @filename: the URI for matching
232 *
233 * input from FILE *, supports compressed input
234 * if @filename is " " then the standard input is used
235 *
236 * Returns an I/O context or NULL in case of error
237 */
238void *
239xmlFileOpen (const char *filename) {
240 const char *path = NULL;
241 FILE *fd;
242
243 if (!strcmp(filename, "-")) {
244 fd = stdin;
245 return((void *) fd);
246 }
247
248 if (!strncmp(filename, "file://localhost", 16))
249 path = &filename[16];
250 else if (!strncmp(filename, "file:///", 8))
251 path = &filename[8];
252 else
253 path = filename;
254 if (path == NULL)
255 return(NULL);
256
257#ifdef WIN32
258 fd = fopen(path, "rb");
259#else
260 fd = fopen(path, "r");
261#endif /* WIN32 */
262 return((void *) fd);
263}
264
265/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000266 * xmlFileOpenW:
267 * @filename: the URI for matching
268 *
269 * output to from FILE *,
270 * if @filename is "-" then the standard output is used
271 *
272 * Returns an I/O context or NULL in case of error
273 */
274void *
275xmlFileOpenW (const char *filename) {
276 const char *path = NULL;
277 FILE *fd;
278
279 if (!strcmp(filename, "-")) {
280 fd = stdout;
281 return((void *) fd);
282 }
283
284 if (!strncmp(filename, "file://localhost", 16))
285 path = &filename[16];
286 else if (!strncmp(filename, "file:///", 8))
287 path = &filename[8];
288 else
289 path = filename;
290 if (path == NULL)
291 return(NULL);
292
293 fd = fopen(path, "w");
294 return((void *) fd);
295}
296
297/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000298 * xmlFileRead:
299 * @context: the I/O context
300 * @buffer: where to drop data
301 * @len: number of bytes to write
302 *
303 * Read @len bytes to @buffer from the I/O channel.
304 *
305 * Returns the number of bytes written
306 */
307int
308xmlFileRead (void * context, char * buffer, int len) {
309 return(fread(&buffer[0], 1, len, (FILE *) context));
310}
311
312/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000313 * xmlFileWrite:
314 * @context: the I/O context
315 * @buffer: where to drop data
316 * @len: number of bytes to write
317 *
318 * Write @len bytes from @buffer to the I/O channel.
319 *
320 * Returns the number of bytes written
321 */
322int
323xmlFileWrite (void * context, const char * buffer, int len) {
324 return(fwrite(&buffer[0], 1, len, (FILE *) context));
325}
326
327/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000328 * xmlFileClose:
329 * @context: the I/O context
330 *
331 * Close an I/O channel
332 */
333void
334xmlFileClose (void * context) {
335 fclose((FILE *) context);
336}
337
338#ifdef HAVE_ZLIB_H
339/************************************************************************
340 * *
341 * I/O for compressed file accesses *
342 * *
343 ************************************************************************/
344/**
345 * xmlGzfileMatch:
346 * @filename: the URI for matching
347 *
348 * input from compressed file test
349 *
350 * Returns 1 if matches, 0 otherwise
351 */
352int
353xmlGzfileMatch (const char *filename) {
354 return(1);
355}
356
357/**
358 * xmlGzfileOpen:
359 * @filename: the URI for matching
360 *
361 * input from compressed file open
362 * if @filename is " " then the standard input is used
363 *
364 * Returns an I/O context or NULL in case of error
365 */
366void *
367xmlGzfileOpen (const char *filename) {
368 const char *path = NULL;
369 gzFile fd;
370
371 if (!strcmp(filename, "-")) {
372 fd = gzdopen (fileno(stdin), "r");
373 return((void *) fd);
374 }
375
376 if (!strncmp(filename, "file://localhost", 16))
377 path = &filename[16];
378 else if (!strncmp(filename, "file:///", 8))
379 path = &filename[8];
380 else
381 path = filename;
382
383 fd = gzopen(filename, "r");
384 return((void *) fd);
385}
386
387/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000388 * xmlGzfileOpenW:
389 * @filename: the URI for matching
390 * @compression: the compression factor (0 - 9 included)
391 *
392 * input from compressed file open
393 * if @filename is " " then the standard input is used
394 *
395 * Returns an I/O context or NULL in case of error
396 */
397void *
398xmlGzfileOpenW (const char *filename, int compression) {
399 const char *path = NULL;
400 char mode[15];
401 gzFile fd;
402
403 sprintf(mode, "w%d", compression);
404 if (!strcmp(filename, "-")) {
405 fd = gzdopen(1, mode);
406 return((void *) fd);
407 }
408
409 if (!strncmp(filename, "file://localhost", 16))
410 path = &filename[16];
411 else if (!strncmp(filename, "file:///", 8))
412 path = &filename[8];
413 else
414 path = filename;
415
416 fd = gzopen(filename, mode);
417 return((void *) fd);
418}
419
420/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000421 * xmlGzfileRead:
422 * @context: the I/O context
423 * @buffer: where to drop data
424 * @len: number of bytes to write
425 *
426 * Read @len bytes to @buffer from the compressed I/O channel.
427 *
428 * Returns the number of bytes written
429 */
430int
431xmlGzfileRead (void * context, char * buffer, int len) {
432 return(gzread((gzFile) context, &buffer[0], len));
433}
434
435/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000436 * xmlGzfileWrite:
437 * @context: the I/O context
438 * @buffer: where to drop data
439 * @len: number of bytes to write
440 *
441 * Write @len bytes from @buffer to the compressed I/O channel.
442 *
443 * Returns the number of bytes written
444 */
445int
446xmlGzfileWrite (void * context, const char * buffer, int len) {
447 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
448}
449
450/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000451 * xmlGzfileClose:
452 * @context: the I/O context
453 *
454 * Close a compressed I/O channel
455 */
456void
457xmlGzfileClose (void * context) {
458 gzclose((gzFile) context);
459}
460#endif /* HAVE_ZLIB_H */
461
462#ifdef LIBXML_HTTP_ENABLED
463/************************************************************************
464 * *
465 * I/O for HTTP file accesses *
466 * *
467 ************************************************************************/
468/**
469 * xmlIOHTTPMatch:
470 * @filename: the URI for matching
471 *
472 * check if the URI matches an HTTP one
473 *
474 * Returns 1 if matches, 0 otherwise
475 */
476int
477xmlIOHTTPMatch (const char *filename) {
478 if (!strncmp(filename, "http://", 7))
479 return(1);
480 return(0);
481}
482
483/**
484 * xmlIOHTTPOpen:
485 * @filename: the URI for matching
486 *
487 * open an HTTP I/O channel
488 *
489 * Returns an I/O context or NULL in case of error
490 */
491void *
492xmlIOHTTPOpen (const char *filename) {
493 return(xmlNanoHTTPOpen(filename, NULL));
494}
495
496/**
497 * xmlIOHTTPRead:
498 * @context: the I/O context
499 * @buffer: where to drop data
500 * @len: number of bytes to write
501 *
502 * Read @len bytes to @buffer from the I/O channel.
503 *
504 * Returns the number of bytes written
505 */
506int
507xmlIOHTTPRead(void * context, char * buffer, int len) {
508 return(xmlNanoHTTPRead(context, &buffer[0], len));
509}
510
511/**
512 * xmlIOHTTPClose:
513 * @context: the I/O context
514 *
515 * Close an HTTP I/O channel
516 */
517void
518xmlIOHTTPClose (void * context) {
519 xmlNanoHTTPClose(context);
520}
521#endif /* LIBXML_HTTP_ENABLED */
522
523#ifdef LIBXML_FTP_ENABLED
524/************************************************************************
525 * *
526 * I/O for FTP file accesses *
527 * *
528 ************************************************************************/
529/**
530 * xmlIOFTPMatch:
531 * @filename: the URI for matching
532 *
533 * check if the URI matches an FTP one
534 *
535 * Returns 1 if matches, 0 otherwise
536 */
537int
538xmlIOFTPMatch (const char *filename) {
539 if (!strncmp(filename, "ftp://", 6))
540 return(1);
541 return(0);
542}
543
544/**
545 * xmlIOFTPOpen:
546 * @filename: the URI for matching
547 *
548 * open an FTP I/O channel
549 *
550 * Returns an I/O context or NULL in case of error
551 */
552void *
553xmlIOFTPOpen (const char *filename) {
554 return(xmlNanoFTPOpen(filename));
555}
556
557/**
558 * xmlIOFTPRead:
559 * @context: the I/O context
560 * @buffer: where to drop data
561 * @len: number of bytes to write
562 *
563 * Read @len bytes to @buffer from the I/O channel.
564 *
565 * Returns the number of bytes written
566 */
567int
568xmlIOFTPRead(void * context, char * buffer, int len) {
569 return(xmlNanoFTPRead(context, &buffer[0], len));
570}
571
572/**
573 * xmlIOFTPClose:
574 * @context: the I/O context
575 *
576 * Close an FTP I/O channel
577 */
578void
579xmlIOFTPClose (void * context) {
580 xmlNanoFTPClose(context);
581}
582#endif /* LIBXML_FTP_ENABLED */
583
584
585/**
586 * xmlRegisterInputCallbacks:
587 * @match: the xmlInputMatchCallback
588 * @open: the xmlInputOpenCallback
589 * @read: the xmlInputReadCallback
590 * @close: the xmlInputCloseCallback
591 *
592 * Register a new set of I/O callback for handling parser input.
593 *
594 * Returns the registered handler number or -1 in case of error
595 */
596int
597xmlRegisterInputCallbacks(xmlInputMatchCallback match,
598 xmlInputOpenCallback open, xmlInputReadCallback read,
599 xmlInputCloseCallback close) {
600 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
601 return(-1);
602 }
603 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match;
604 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open;
605 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read;
606 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close;
607 return(xmlInputCallbackNr++);
608}
609
610/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000611 * xmlRegisterOutputCallbacks:
612 * @match: the xmlOutputMatchCallback
613 * @open: the xmlOutputOpenCallback
614 * @write: the xmlOutputWriteCallback
615 * @close: the xmlOutputCloseCallback
616 *
617 * Register a new set of I/O callback for handling output.
618 *
619 * Returns the registered handler number or -1 in case of error
620 */
621int
622xmlRegisterOutputCallbacks(xmlOutputMatchCallback match,
623 xmlOutputOpenCallback open, xmlOutputWriteCallback write,
624 xmlOutputCloseCallback close) {
625 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
626 return(-1);
627 }
628 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = match;
629 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = open;
630 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = write;
631 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = close;
632 return(xmlOutputCallbackNr++);
633}
634
635/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000636 * xmlRegisterDefaultInputCallbacks:
637 *
638 * Registers the default compiled-in I/O handlers.
639 */
640void
641xmlRegisterDefaultInputCallbacks(void) {
642 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
643 xmlFileRead, xmlFileClose);
644#ifdef HAVE_ZLIB_H
645 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
646 xmlGzfileRead, xmlGzfileClose);
647#endif /* HAVE_ZLIB_H */
648
649#ifdef LIBXML_HTTP_ENABLED
650 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
651 xmlIOHTTPRead, xmlIOHTTPClose);
652#endif /* LIBXML_HTTP_ENABLED */
653
654#ifdef LIBXML_FTP_ENABLED
655 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
656 xmlIOFTPRead, xmlIOFTPClose);
657#endif /* LIBXML_FTP_ENABLED */
658}
659
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000660/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000661 * xmlRegisterDefaultOutputCallbacks:
662 *
663 * Registers the default compiled-in I/O handlers.
664 */
665void
666xmlRegisterDefaultOutputCallbacks(void) {
667 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
668 xmlFileWrite, xmlFileClose);
669/*********************************
670 No way a-priori to distinguish between gzipped files from
671 uncompressed ones except opening if existing then closing
672 and saving with same compression ratio ... a pain.
673
674#ifdef HAVE_ZLIB_H
675 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
676 xmlGzfileWrite, xmlGzfileClose);
677#endif
678 No HTTP PUT support yet, patches welcome
679
680#ifdef LIBXML_HTTP_ENABLED
681 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
682 xmlIOHTTPWrite, xmlIOHTTPClose);
683#endif
684
685 Nor FTP PUT ....
686#ifdef LIBXML_FTP_ENABLED
687 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
688 xmlIOFTPWrite, xmlIOFTPClose);
689#endif
690 **********************************/
691}
692
693/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000694 * xmlAllocParserInputBuffer:
695 * @enc: the charset encoding if known
696 *
697 * Create a buffered parser input for progressive parsing
698 *
699 * Returns the new parser input or NULL
700 */
701xmlParserInputBufferPtr
702xmlAllocParserInputBuffer(xmlCharEncoding enc) {
703 xmlParserInputBufferPtr ret;
704
Daniel Veillard6454aec1999-09-02 22:04:43 +0000705 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000706 if (ret == NULL) {
707 fprintf(stderr, "xmlAllocParserInputBuffer : out of memory!\n");
708 return(NULL);
709 }
710 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
711 ret->buffer = xmlBufferCreate();
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000712 if (ret->buffer == NULL) {
713 xmlFree(ret);
714 return(NULL);
715 }
716 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000717 ret->encoder = xmlGetCharEncodingHandler(enc);
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000718 if (ret->encoder != NULL)
719 ret->raw = xmlBufferCreate();
720 else
721 ret->raw = NULL;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000722 ret->readcallback = NULL;
723 ret->closecallback = NULL;
724 ret->context = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000725
726 return(ret);
727}
728
729/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000730 * xmlAllocOutputBuffer:
731 * @encoder: the encoding converter or NULL
732 *
733 * Create a buffered parser output
734 *
735 * Returns the new parser output or NULL
736 */
737xmlOutputBufferPtr
738xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
739 xmlOutputBufferPtr ret;
740
741 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
742 if (ret == NULL) {
743 fprintf(stderr, "xmlAllocOutputBuffer : out of memory!\n");
744 return(NULL);
745 }
746 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
747 ret->buffer = xmlBufferCreate();
748 if (ret->buffer == NULL) {
749 xmlFree(ret);
750 return(NULL);
751 }
752 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
753 ret->encoder = encoder;
754 if (encoder != NULL) {
755 ret->conv = xmlBufferCreateSize(4000);
756 /*
757 * This call is designed to initiate the encoder state
758 */
759 xmlCharEncOutFunc(encoder, ret->conv, NULL);
760 } else
761 ret->conv = NULL;
762 ret->writecallback = NULL;
763 ret->closecallback = NULL;
764 ret->context = NULL;
765 ret->written = 0;
766
767 return(ret);
768}
769
770/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000771 * xmlFreeParserInputBuffer:
772 * @in: a buffered parser input
773 *
774 * Free up the memory used by a buffered parser input
775 */
776void
777xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000778 if (in->raw) {
779 xmlBufferFree(in->raw);
780 in->raw = NULL;
781 }
782 if (in->encoder != NULL) {
783 xmlCharEncCloseFunc(in->encoder);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000784 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000785 if (in->closecallback != NULL) {
786 in->closecallback(in->context);
787 }
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000788 if (in->buffer != NULL) {
789 xmlBufferFree(in->buffer);
790 in->buffer = NULL;
791 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000792
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000793 memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000794 xmlFree(in);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000795}
796
797/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000798 * xmlOutputBufferClose:
799 * @out: a buffered output
800 *
801 * flushes and close the output I/O channel
802 * and free up all the associated resources
803 *
804 * Returns the number of byte written or -1 in case of error.
805 */
806int
807xmlOutputBufferClose(xmlOutputBufferPtr out) {
808 int written;
809
810 if (out == NULL)
811 return(-1);
812 xmlOutputBufferFlush(out);
813 if (out->closecallback != NULL) {
814 out->closecallback(out->context);
815 }
816 written = out->written;
817 if (out->conv) {
818 xmlBufferFree(out->conv);
819 out->conv = NULL;
820 }
821 if (out->encoder != NULL) {
822 xmlCharEncCloseFunc(out->encoder);
823 }
824 if (out->buffer != NULL) {
825 xmlBufferFree(out->buffer);
826 out->buffer = NULL;
827 }
828
829 memset(out, 0xbe, (size_t) sizeof(xmlOutputBuffer));
830 xmlFree(out);
831 return(written);
832}
833
834/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000835 * xmlParserInputBufferCreateFilename:
Daniel Veillard5d211f42000-04-07 17:00:24 +0000836 * @URI: a C string containing the URI or filename
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000837 * @enc: the charset encoding if known
838 *
839 * Create a buffered parser input for the progressive parsing of a file
840 * If filename is "-' then we use stdin as the input.
841 * Automatic support for ZLIB/Compress compressed document is provided
842 * by default if found at compile-time.
Daniel Veillardcf461992000-03-14 18:30:20 +0000843 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000844 *
845 * Returns the new parser input or NULL
846 */
847xmlParserInputBufferPtr
Daniel Veillard5d211f42000-04-07 17:00:24 +0000848xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000849 xmlParserInputBufferPtr ret;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000850 int i;
851 void *context = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000852
Daniel Veillard5d211f42000-04-07 17:00:24 +0000853 if (xmlInputCallbackInitialized == 0)
854 xmlRegisterDefaultInputCallbacks();
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000855
Daniel Veillard5d211f42000-04-07 17:00:24 +0000856 if (URI == NULL) return(NULL);
857
858 /*
859 * Try to find one of the input accept method accepting taht scheme
860 * Go in reverse to give precedence to user defined handlers.
861 */
862 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
863 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
864 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
865 context = xmlInputCallbackTable[i].opencallback(URI);
866 if (context != NULL)
867 break;
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000868 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000869 }
870 if (context == NULL) {
871#ifdef DEBUG_INPUT
872 fprintf(stderr, "No input filter matching \"%s\"\n", URI);
Daniel Veillardda07c342000-01-25 18:31:22 +0000873#endif
Daniel Veillard5d211f42000-04-07 17:00:24 +0000874 return(NULL);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000875 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000876
Daniel Veillardcf461992000-03-14 18:30:20 +0000877 /*
878 * Allocate the Input buffer front-end.
879 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000880 ret = xmlAllocParserInputBuffer(enc);
881 if (ret != NULL) {
Daniel Veillard5d211f42000-04-07 17:00:24 +0000882 ret->context = context;
883 ret->readcallback = xmlInputCallbackTable[i].readcallback;
884 ret->closecallback = xmlInputCallbackTable[i].closecallback;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000885 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000886 return(ret);
887}
888
889/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000890 * xmlOutputBufferCreateFilename:
891 * @URI: a C string containing the URI or filename
892 * @encoder: the encoding converter or NULL
893 * @compression: the compression ration (0 none, 9 max).
894 *
895 * Create a buffered output for the progressive saving of a file
896 * If filename is "-' then we use stdout as the output.
897 * Automatic support for ZLIB/Compress compressed document is provided
898 * by default if found at compile-time.
899 * TODO: currently if compression is set, the library only support
900 * writing to a local file.
901 *
902 * Returns the new output or NULL
903 */
904xmlOutputBufferPtr
905xmlOutputBufferCreateFilename(const char *URI,
906 xmlCharEncodingHandlerPtr encoder,
907 int compression) {
908 xmlOutputBufferPtr ret;
909 int i;
910 void *context = NULL;
911
912 if (xmlOutputCallbackInitialized == 0)
913 xmlRegisterDefaultOutputCallbacks();
914
915 if (URI == NULL) return(NULL);
916
917#ifdef HAVE_ZLIB_H
918 if ((compression > 0) && (compression <= 9)) {
919 context = xmlGzfileOpenW(URI, compression);
920 if (context != NULL) {
921 ret = xmlAllocOutputBuffer(encoder);
922 if (ret != NULL) {
923 ret->context = context;
924 ret->writecallback = xmlGzfileWrite;
925 ret->closecallback = xmlGzfileClose;
926 }
927 return(ret);
928 }
929 }
930#endif
931
932 /*
933 * Try to find one of the output accept method accepting taht scheme
934 * Go in reverse to give precedence to user defined handlers.
935 */
936 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
937 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
938 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
939 context = xmlOutputCallbackTable[i].opencallback(URI);
940 if (context != NULL)
941 break;
942 }
943 }
944 if (context == NULL) {
945#ifdef DEBUG_INPUT
946 fprintf(stderr, "No output filter matching \"%s\"\n", URI);
947#endif
948 return(NULL);
949 }
950
951 /*
952 * Allocate the Output buffer front-end.
953 */
954 ret = xmlAllocOutputBuffer(encoder);
955 if (ret != NULL) {
956 ret->context = context;
957 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
958 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
959 }
960 return(ret);
961}
962
963/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000964 * xmlParserInputBufferCreateFile:
965 * @file: a FILE*
966 * @enc: the charset encoding if known
967 *
968 * Create a buffered parser input for the progressive parsing of a FILE *
969 * buffered C I/O
970 *
971 * Returns the new parser input or NULL
972 */
973xmlParserInputBufferPtr
974xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
975 xmlParserInputBufferPtr ret;
976
Daniel Veillard5d211f42000-04-07 17:00:24 +0000977 if (xmlInputCallbackInitialized == 0)
978 xmlRegisterDefaultInputCallbacks();
979
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000980 if (file == NULL) return(NULL);
981
982 ret = xmlAllocParserInputBuffer(enc);
Daniel Veillard5d211f42000-04-07 17:00:24 +0000983 if (ret != NULL) {
984 ret->context = file;
985 ret->readcallback = xmlFileRead;
986 ret->closecallback = xmlFileClose;
987 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000988
989 return(ret);
990}
991
992/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000993 * xmlOutputBufferCreateFile:
994 * @file: a FILE*
995 * @encoder: the encoding converter or NULL
996 *
997 * Create a buffered output for the progressive saving to a FILE *
998 * buffered C I/O
999 *
1000 * Returns the new parser output or NULL
1001 */
1002xmlOutputBufferPtr
1003xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1004 xmlOutputBufferPtr ret;
1005
1006 if (xmlOutputCallbackInitialized == 0)
1007 xmlRegisterDefaultOutputCallbacks();
1008
1009 if (file == NULL) return(NULL);
1010
1011 ret = xmlAllocOutputBuffer(encoder);
1012 if (ret != NULL) {
1013 ret->context = file;
1014 ret->writecallback = xmlFileWrite;
1015 ret->closecallback = xmlFileClose;
1016 }
1017
1018 return(ret);
1019}
1020
1021/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001022 * xmlParserInputBufferCreateFd:
1023 * @fd: a file descriptor number
1024 * @enc: the charset encoding if known
1025 *
1026 * Create a buffered parser input for the progressive parsing for the input
1027 * from a file descriptor
1028 *
1029 * Returns the new parser input or NULL
1030 */
1031xmlParserInputBufferPtr
1032xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1033 xmlParserInputBufferPtr ret;
1034
1035 if (fd < 0) return(NULL);
1036
1037 ret = xmlAllocParserInputBuffer(enc);
Daniel Veillard5d211f42000-04-07 17:00:24 +00001038 if (ret != NULL) {
1039 ret->context = (void *) fd;
1040 ret->readcallback = xmlFdRead;
1041 ret->closecallback = xmlFdClose;
1042 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001043
1044 return(ret);
1045}
1046
1047/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001048 * xmlOutputBufferCreateFd:
1049 * @fd: a file descriptor number
1050 * @encoder: the encoding converter or NULL
1051 *
1052 * Create a buffered output for the progressive saving
1053 * to a file descriptor
1054 *
1055 * Returns the new parser output or NULL
1056 */
1057xmlOutputBufferPtr
1058xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1059 xmlOutputBufferPtr ret;
1060
1061 if (fd < 0) return(NULL);
1062
1063 ret = xmlAllocOutputBuffer(encoder);
1064 if (ret != NULL) {
1065 ret->context = (void *) fd;
1066 ret->writecallback = xmlFdWrite;
1067 ret->closecallback = xmlFdClose;
1068 }
1069
1070 return(ret);
1071}
1072
1073/**
Daniel Veillard5e873c42000-04-12 13:27:38 +00001074 * xmlParserInputBufferCreateIO:
1075 * @ioread: an I/O read function
1076 * @ioclose: an I/O close function
1077 * @ioctx: an I/O handler
1078 * @enc: the charset encoding if known
1079 *
1080 * Create a buffered parser input for the progressive parsing for the input
Daniel Veillardbe803962000-06-28 23:40:59 +00001081 * from an I/O handler
Daniel Veillard5e873c42000-04-12 13:27:38 +00001082 *
1083 * Returns the new parser input or NULL
1084 */
1085xmlParserInputBufferPtr
1086xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1087 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1088 xmlParserInputBufferPtr ret;
1089
1090 if (ioread == NULL) return(NULL);
1091
1092 ret = xmlAllocParserInputBuffer(enc);
1093 if (ret != NULL) {
1094 ret->context = (void *) ioctx;
1095 ret->readcallback = ioread;
1096 ret->closecallback = ioclose;
1097 }
1098
1099 return(ret);
1100}
1101
1102/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001103 * xmlOutputBufferCreateIO:
1104 * @iowrite: an I/O write function
1105 * @ioclose: an I/O close function
1106 * @ioctx: an I/O handler
1107 * @enc: the charset encoding if known
1108 *
1109 * Create a buffered output for the progressive saving
1110 * to an I/O handler
1111 *
1112 * Returns the new parser output or NULL
1113 */
1114xmlOutputBufferPtr
1115xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1116 xmlOutputCloseCallback ioclose, void *ioctx,
1117 xmlCharEncodingHandlerPtr encoder) {
1118 xmlOutputBufferPtr ret;
1119
1120 if (iowrite == NULL) return(NULL);
1121
1122 ret = xmlAllocOutputBuffer(encoder);
1123 if (ret != NULL) {
1124 ret->context = (void *) ioctx;
1125 ret->writecallback = iowrite;
1126 ret->closecallback = ioclose;
1127 }
1128
1129 return(ret);
1130}
1131
1132/**
Daniel Veillard7f858501999-11-17 17:32:38 +00001133 * xmlParserInputBufferPush:
1134 * @in: a buffered parser input
Daniel Veillard7f858501999-11-17 17:32:38 +00001135 * @len: the size in bytes of the array.
Daniel Veillardbe803962000-06-28 23:40:59 +00001136 * @buf: an char array
Daniel Veillard7f858501999-11-17 17:32:38 +00001137 *
1138 * Push the content of the arry in the input buffer
1139 * This routine handle the I18N transcoding to internal UTF-8
1140 * This is used when operating the parser in progressive (push) mode.
1141 *
1142 * Returns the number of chars read and stored in the buffer, or -1
1143 * in case of error.
1144 */
1145int
Daniel Veillarda819dac1999-11-24 18:04:22 +00001146xmlParserInputBufferPush(xmlParserInputBufferPtr in, int len, const char *buf) {
Daniel Veillard7f858501999-11-17 17:32:38 +00001147 int nbchars = 0;
1148
1149 if (len < 0) return(0);
1150 if (in->encoder != NULL) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001151 /*
1152 * Store the data in the incoming raw buffer
Daniel Veillard7f858501999-11-17 17:32:38 +00001153 */
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001154 if (in->raw == NULL) {
1155 in->raw = xmlBufferCreate();
1156 }
1157 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1158
1159 /*
1160 * convert as much as possible to the parser reading buffer.
1161 */
1162 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
Daniel Veillardcf461992000-03-14 18:30:20 +00001163 if (nbchars < 0) {
1164 fprintf(stderr, "xmlParserInputBufferPush: encoder error\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00001165 return(-1);
1166 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001167 } else {
1168 nbchars = len;
1169 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
Daniel Veillard7f858501999-11-17 17:32:38 +00001170 }
1171#ifdef DEBUG_INPUT
1172 fprintf(stderr, "I/O: pushed %d chars, buffer %d/%d\n",
1173 nbchars, in->buffer->use, in->buffer->size);
1174#endif
1175 return(nbchars);
1176}
1177
1178/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001179 * xmlParserInputBufferGrow:
1180 * @in: a buffered parser input
1181 * @len: indicative value of the amount of chars to read
1182 *
1183 * Grow up the content of the input buffer, the old data are preserved
1184 * This routine handle the I18N transcoding to internal UTF-8
Daniel Veillard7f858501999-11-17 17:32:38 +00001185 * This routine is used when operating the parser in normal (pull) mode
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001186 *
1187 * TODO: one should be able to remove one extra copy by copying directy
1188 * onto in->buffer or in->raw
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001189 *
1190 * Returns the number of chars read and stored in the buffer, or -1
1191 * in case of error.
1192 */
1193int
1194xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1195 char *buffer = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001196 int res = 0;
1197 int nbchars = 0;
1198 int buffree;
1199
1200 if ((len <= MINLEN) && (len != 4))
1201 len = MINLEN;
1202 buffree = in->buffer->size - in->buffer->use;
1203 if (buffree <= 0) {
1204 fprintf(stderr, "xmlParserInputBufferGrow : buffer full !\n");
1205 return(0);
1206 }
1207 if (len > buffree)
1208 len = buffree;
1209
Daniel Veillard6454aec1999-09-02 22:04:43 +00001210 buffer = xmlMalloc((len + 1) * sizeof(char));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001211 if (buffer == NULL) {
1212 fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
1213 return(-1);
1214 }
Daniel Veillard5d211f42000-04-07 17:00:24 +00001215
1216 /*
1217 * Call the read method for this I/O type.
1218 */
1219 if (in->readcallback != NULL) {
1220 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001221 } else {
1222 fprintf(stderr, "xmlParserInputBufferGrow : no input !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001223 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001224 return(-1);
1225 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001226 if (res < 0) {
1227 perror ("read error");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001228 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001229 return(-1);
1230 }
Daniel Veillardbe803962000-06-28 23:40:59 +00001231 len = res;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001232 if (in->encoder != NULL) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001233 /*
1234 * Store the data in the incoming raw buffer
1235 */
1236 if (in->raw == NULL) {
1237 in->raw = xmlBufferCreate();
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001238 }
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001239 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
Daniel Veillardcf461992000-03-14 18:30:20 +00001240
1241 /*
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001242 * convert as much as possible to the parser reading buffer.
Daniel Veillardcf461992000-03-14 18:30:20 +00001243 */
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001244 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1245 if (nbchars < 0) {
1246 fprintf(stderr, "xmlParserInputBufferGrow: encoder error\n");
1247 return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00001248 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001249 } else {
Daniel Veillardbe803962000-06-28 23:40:59 +00001250 nbchars = len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001251 buffer[nbchars] = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001252 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001253 }
1254#ifdef DEBUG_INPUT
1255 fprintf(stderr, "I/O: read %d chars, buffer %d/%d\n",
1256 nbchars, in->buffer->use, in->buffer->size);
1257#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001258 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001259 return(nbchars);
1260}
1261
1262/**
1263 * xmlParserInputBufferRead:
1264 * @in: a buffered parser input
1265 * @len: indicative value of the amount of chars to read
1266 *
1267 * Refresh the content of the input buffer, the old data are considered
1268 * consumed
1269 * This routine handle the I18N transcoding to internal UTF-8
1270 *
1271 * Returns the number of chars read and stored in the buffer, or -1
1272 * in case of error.
1273 */
1274int
1275xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1276 /* xmlBufferEmpty(in->buffer); */
Daniel Veillard5d211f42000-04-07 17:00:24 +00001277 if (in->readcallback != NULL)
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001278 return(xmlParserInputBufferGrow(in, len));
1279 else
Daniel Veillardbe803962000-06-28 23:40:59 +00001280 return(-1);
1281}
1282
1283/**
1284 * xmlOutputBufferWrite:
1285 * @out: a buffered parser output
1286 * @len: the size in bytes of the array.
1287 * @buf: an char array
1288 *
1289 * Write the content of the array in the output I/O buffer
1290 * This routine handle the I18N transcoding from internal UTF-8
1291 * The buffer is lossless, i.e. will store in case of partial
1292 * or delayed writes.
1293 *
1294 * Returns the number of chars immediately written, or -1
1295 * in case of error.
1296 */
1297int
1298xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
1299 int nbchars = 0, ret;
1300
1301 if (len < 0) return(0);
1302
1303 /*
1304 * first handle encoding stuff.
1305 */
1306 if (out->encoder != NULL) {
1307 /*
1308 * Store the data in the incoming raw buffer
1309 */
1310 if (out->conv == NULL) {
1311 out->conv = xmlBufferCreate();
1312 }
1313 xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1314
1315 if (out->buffer->use < MINLEN)
1316 return(0);
1317
1318 /*
1319 * convert as much as possible to the parser reading buffer.
1320 */
1321 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1322 if (nbchars < 0) {
1323 fprintf(stderr, "xmlOutputBufferWrite: encoder error\n");
1324 return(-1);
1325 }
1326 nbchars = out->conv->use;
1327 } else {
1328 xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1329 nbchars = out->buffer->use;
1330 }
1331 if (nbchars < MINLEN)
1332 return(0);
1333
1334 /*
1335 * second write the stuff to the I/O channel
1336 */
1337 if (out->encoder != NULL) {
1338 ret = out->writecallback(out->context,
1339 (const char *)out->conv->content, nbchars);
1340 if (ret >= 0)
1341 xmlBufferShrink(out->conv, nbchars);
1342 } else {
1343 ret = out->writecallback(out->context,
1344 (const char *)out->buffer->content, nbchars);
1345 if (ret >= 0)
1346 xmlBufferShrink(out->buffer, nbchars);
1347 }
1348 if (ret < 0) {
1349 fprintf(stderr, "I/O: error %d writing %d bytes\n", ret, nbchars);
1350 return(ret);
1351 }
1352 out->written += ret;
1353
1354#ifdef DEBUG_INPUT
1355 fprintf(stderr, "I/O: wrote %d chars\n", ret);
1356#endif
1357 return(nbchars);
1358}
1359
1360/**
1361 * xmlOutputBufferWriteString:
1362 * @out: a buffered parser output
1363 * @str: a zero terminated C string
1364 *
1365 * Write the content of the string in the output I/O buffer
1366 * This routine handle the I18N transcoding from internal UTF-8
1367 * The buffer is lossless, i.e. will store in case of partial
1368 * or delayed writes.
1369 *
1370 * Returns the number of chars immediately written, or -1
1371 * in case of error.
1372 */
1373int
1374xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
1375 int len;
1376
1377 if (str == NULL)
1378 return(-1);
1379 len = strlen(str);
1380
1381 if (len > 0)
1382 return(xmlOutputBufferWrite(out, len, str));
1383 return(len);
1384}
1385
1386/**
1387 * xmlOutputBufferFlush:
1388 * @out: a buffered output
1389 *
1390 * flushes the output I/O channel
1391 *
1392 * Returns the number of byte written or -1 in case of error.
1393 */
1394int
1395xmlOutputBufferFlush(xmlOutputBufferPtr out) {
1396 int nbchars = 0, ret;
1397
1398 /*
1399 * first handle encoding stuff.
1400 */
1401 if ((out->conv != NULL) && (out->encoder != NULL)) {
1402 /*
1403 * convert as much as possible to the parser reading buffer.
1404 */
1405 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1406 if (nbchars < 0) {
1407 fprintf(stderr, "xmlOutputBufferWrite: encoder error\n");
1408 return(-1);
1409 }
1410 }
1411
1412 /*
1413 * second flush the stuff to the I/O channel
1414 */
1415 if ((out->conv != NULL) && (out->encoder != NULL)) {
1416 ret = out->writecallback(out->context,
1417 (const char *)out->conv->content, out->conv->use);
1418 if (ret >= 0)
1419 xmlBufferShrink(out->conv, ret);
1420 } else {
1421 ret = out->writecallback(out->context,
1422 (const char *)out->buffer->content, out->buffer->use);
1423 if (ret >= 0)
1424 xmlBufferShrink(out->buffer, ret);
1425 }
1426 if (ret < 0) {
1427 fprintf(stderr, "I/O: error %d flushing %d bytes\n", ret, nbchars);
1428 return(ret);
1429 }
1430 out->written += ret;
1431
1432#ifdef DEBUG_INPUT
1433 fprintf(stderr, "I/O: flushed %d chars\n", ret);
1434#endif
1435 return(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001436}
1437
Daniel Veillardb05deb71999-08-10 19:04:08 +00001438/*
1439 * xmlParserGetDirectory:
1440 * @filename: the path to a file
1441 *
1442 * lookup the directory for that file
1443 *
1444 * Returns a new allocated string containing the directory, or NULL.
1445 */
1446char *
1447xmlParserGetDirectory(const char *filename) {
1448 char *ret = NULL;
1449 char dir[1024];
1450 char *cur;
1451 char sep = '/';
1452
Daniel Veillard5d211f42000-04-07 17:00:24 +00001453 if (xmlInputCallbackInitialized == 0)
1454 xmlRegisterDefaultInputCallbacks();
1455
Daniel Veillardb05deb71999-08-10 19:04:08 +00001456 if (filename == NULL) return(NULL);
1457#ifdef WIN32
1458 sep = '\\';
1459#endif
1460
1461 strncpy(dir, filename, 1023);
1462 dir[1023] = 0;
1463 cur = &dir[strlen(dir)];
1464 while (cur > dir) {
1465 if (*cur == sep) break;
1466 cur --;
1467 }
1468 if (*cur == sep) {
1469 if (cur == dir) dir[1] = 0;
1470 else *cur = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001471 ret = xmlMemStrdup(dir);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001472 } else {
1473 if (getcwd(dir, 1024) != NULL) {
1474 dir[1023] = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001475 ret = xmlMemStrdup(dir);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001476 }
1477 }
1478 return(ret);
1479}
1480
Daniel Veillardb96e6431999-08-29 21:02:19 +00001481/****************************************************************
1482 * *
1483 * External entities loading *
1484 * *
1485 ****************************************************************/
1486
1487/*
1488 * xmlDefaultExternalEntityLoader:
1489 * @URL: the URL for the entity to load
1490 * @ID: the System ID for the entity to load
Daniel Veillard686d6b62000-01-03 11:08:02 +00001491 * @ctxt: the context in which the entity is called or NULL
Daniel Veillardb96e6431999-08-29 21:02:19 +00001492 *
1493 * By default we don't load external entitites, yet.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001494 *
1495 * Returns a new allocated xmlParserInputPtr, or NULL.
1496 */
1497static
1498xmlParserInputPtr
1499xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillard686d6b62000-01-03 11:08:02 +00001500 xmlParserCtxtPtr ctxt) {
1501 xmlParserInputPtr ret = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001502#ifdef DEBUG_EXTERNAL_ENTITIES
1503 fprintf(stderr, "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
1504#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001505 if (URL == NULL) {
1506 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1507 ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n",
1508 ID);
1509 return(NULL);
1510 }
1511 ret = xmlNewInputFromFile(ctxt, URL);
1512 if (ret == NULL) {
1513 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1514 ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n",
1515 URL);
1516 }
1517 return(ret);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001518}
1519
1520static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1521 xmlDefaultExternalEntityLoader;
1522
1523/*
1524 * xmlSetExternalEntityLoader:
1525 * @f: the new entity resolver function
1526 *
1527 * Changes the defaultexternal entity resolver function for the application
1528 */
1529void
1530xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1531 xmlCurrentExternalEntityLoader = f;
1532}
1533
1534/*
1535 * xmlGetExternalEntityLoader:
1536 *
1537 * Get the default external entity resolver function for the application
1538 *
1539 * Returns the xmlExternalEntityLoader function pointer
1540 */
1541xmlExternalEntityLoader
1542xmlGetExternalEntityLoader(void) {
1543 return(xmlCurrentExternalEntityLoader);
1544}
1545
1546/*
1547 * xmlLoadExternalEntity:
1548 * @URL: the URL for the entity to load
1549 * @ID: the System ID for the entity to load
Daniel Veillard686d6b62000-01-03 11:08:02 +00001550 * @ctxt: the context in which the entity is called or NULL
Daniel Veillardb96e6431999-08-29 21:02:19 +00001551 *
1552 * Load an external entity, note that the use of this function for
1553 * unparsed entities may generate problems
1554 * TODO: a more generic External entitiy API must be designed
1555 *
1556 * Returns the xmlParserInputPtr or NULL
1557 */
1558xmlParserInputPtr
1559xmlLoadExternalEntity(const char *URL, const char *ID,
Daniel Veillard686d6b62000-01-03 11:08:02 +00001560 xmlParserCtxtPtr ctxt) {
1561 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001562}
1563