blob: 317291733c8d420080704430fa1443ce6db5230b [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
Daniel Veillard46e370e2000-07-21 20:32:03 +000092int
93xmlNop(void) {
94 return(0);
95}
96
Daniel Veillard5d211f42000-04-07 17:00:24 +000097/**
98 * xmlFdMatch:
99 * @filename: the URI for matching
100 *
101 * input from file descriptor
102 *
103 * Returns 1 if matches, 0 otherwise
104 */
105int
106xmlFdMatch (const char *filename) {
107 return(1);
108}
109
110/**
111 * xmlFdOpen:
112 * @filename: the URI for matching
113 *
114 * input from file descriptor, supports compressed input
115 * if @filename is " " then the standard input is used
116 *
117 * Returns an I/O context or NULL in case of error
118 */
119void *
120xmlFdOpen (const char *filename) {
121 const char *path = NULL;
122 int fd;
123
124 if (!strcmp(filename, "-")) {
125 fd = 0;
126 return((void *) fd);
127 }
128
129 if (!strncmp(filename, "file://localhost", 16))
130 path = &filename[16];
131 else if (!strncmp(filename, "file:///", 8))
132 path = &filename[8];
133 else if (filename[0] == '/')
134 path = filename;
135 if (path == NULL)
136 return(NULL);
137
138#ifdef WIN32
139 fd = _open (filename, O_RDONLY | _O_BINARY);
140#else
141 fd = open (filename, O_RDONLY);
142#endif
143
144 return((void *) fd);
145}
146
147/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000148 * xmlFdOpenW:
149 * @filename: the URI for matching
150 *
151 * input from file descriptor,
152 * if @filename is "-" then the standard output is used
153 *
154 * Returns an I/O context or NULL in case of error
155 */
156void *
157xmlFdOpenW (const char *filename) {
158 const char *path = NULL;
159 int fd;
160
161 if (!strcmp(filename, "-")) {
162 fd = 1;
163 return((void *) fd);
164 }
165
166 if (!strncmp(filename, "file://localhost", 16))
167 path = &filename[16];
168 else if (!strncmp(filename, "file:///", 8))
169 path = &filename[8];
170 else if (filename[0] == '/')
171 path = filename;
172 if (path == NULL)
173 return(NULL);
174
175 fd = open (filename, O_WRONLY);
176
177 return((void *) fd);
178}
179
180/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000181 * xmlFdRead:
182 * @context: the I/O context
183 * @buffer: where to drop data
Daniel Veillardbe803962000-06-28 23:40:59 +0000184 * @len: number of bytes to read
Daniel Veillard5d211f42000-04-07 17:00:24 +0000185 *
186 * Read @len bytes to @buffer from the I/O channel.
187 *
188 * Returns the number of bytes written
189 */
190int
191xmlFdRead (void * context, char * buffer, int len) {
192 return(read((int) context, &buffer[0], len));
193}
194
195/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000196 * xmlFdWrite:
197 * @context: the I/O context
198 * @buffer: where to get data
199 * @len: number of bytes to write
200 *
201 * Write @len bytes from @buffer to the I/O channel.
202 *
203 * Returns the number of bytes written
204 */
205int
206xmlFdWrite (void * context, const char * buffer, int len) {
207 return(write((int) context, &buffer[0], len));
208}
209
210/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000211 * xmlFdClose:
212 * @context: the I/O context
213 *
214 * Close an I/O channel
215 */
216void
217xmlFdClose (void * context) {
218 close((int) context);
219}
220
221/**
222 * xmlFileMatch:
223 * @filename: the URI for matching
224 *
225 * input from FILE *
226 *
227 * Returns 1 if matches, 0 otherwise
228 */
229int
230xmlFileMatch (const char *filename) {
231 return(1);
232}
233
234/**
235 * xmlFileOpen:
236 * @filename: the URI for matching
237 *
238 * input from FILE *, supports compressed input
239 * if @filename is " " then the standard input is used
240 *
241 * Returns an I/O context or NULL in case of error
242 */
243void *
244xmlFileOpen (const char *filename) {
245 const char *path = NULL;
246 FILE *fd;
247
248 if (!strcmp(filename, "-")) {
249 fd = stdin;
250 return((void *) fd);
251 }
252
253 if (!strncmp(filename, "file://localhost", 16))
254 path = &filename[16];
255 else if (!strncmp(filename, "file:///", 8))
256 path = &filename[8];
257 else
258 path = filename;
259 if (path == NULL)
260 return(NULL);
261
262#ifdef WIN32
263 fd = fopen(path, "rb");
264#else
265 fd = fopen(path, "r");
266#endif /* WIN32 */
267 return((void *) fd);
268}
269
270/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000271 * xmlFileOpenW:
272 * @filename: the URI for matching
273 *
274 * output to from FILE *,
275 * if @filename is "-" then the standard output is used
276 *
277 * Returns an I/O context or NULL in case of error
278 */
279void *
280xmlFileOpenW (const char *filename) {
281 const char *path = NULL;
282 FILE *fd;
283
284 if (!strcmp(filename, "-")) {
285 fd = stdout;
286 return((void *) fd);
287 }
288
289 if (!strncmp(filename, "file://localhost", 16))
290 path = &filename[16];
291 else if (!strncmp(filename, "file:///", 8))
292 path = &filename[8];
293 else
294 path = filename;
295 if (path == NULL)
296 return(NULL);
297
298 fd = fopen(path, "w");
299 return((void *) fd);
300}
301
302/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000303 * xmlFileRead:
304 * @context: the I/O context
305 * @buffer: where to drop data
306 * @len: number of bytes to write
307 *
308 * Read @len bytes to @buffer from the I/O channel.
309 *
310 * Returns the number of bytes written
311 */
312int
313xmlFileRead (void * context, char * buffer, int len) {
314 return(fread(&buffer[0], 1, len, (FILE *) context));
315}
316
317/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000318 * xmlFileWrite:
319 * @context: the I/O context
320 * @buffer: where to drop data
321 * @len: number of bytes to write
322 *
323 * Write @len bytes from @buffer to the I/O channel.
324 *
325 * Returns the number of bytes written
326 */
327int
328xmlFileWrite (void * context, const char * buffer, int len) {
329 return(fwrite(&buffer[0], 1, len, (FILE *) context));
330}
331
332/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000333 * xmlFileClose:
334 * @context: the I/O context
335 *
336 * Close an I/O channel
337 */
338void
339xmlFileClose (void * context) {
340 fclose((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 */
357int
358xmlGzfileMatch (const char *filename) {
359 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 */
371void *
372xmlGzfileOpen (const char *filename) {
373 const char *path = NULL;
374 gzFile fd;
375
376 if (!strcmp(filename, "-")) {
377 fd = gzdopen (fileno(stdin), "r");
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[8];
385 else
386 path = filename;
387
388 fd = gzopen(filename, "r");
389 return((void *) fd);
390}
391
392/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000393 * xmlGzfileOpenW:
394 * @filename: the URI for matching
395 * @compression: the compression factor (0 - 9 included)
396 *
397 * input from compressed file open
398 * if @filename is " " then the standard input is used
399 *
400 * Returns an I/O context or NULL in case of error
401 */
402void *
403xmlGzfileOpenW (const char *filename, int compression) {
404 const char *path = NULL;
405 char mode[15];
406 gzFile fd;
407
408 sprintf(mode, "w%d", compression);
409 if (!strcmp(filename, "-")) {
410 fd = gzdopen(1, mode);
411 return((void *) fd);
412 }
413
414 if (!strncmp(filename, "file://localhost", 16))
415 path = &filename[16];
416 else if (!strncmp(filename, "file:///", 8))
417 path = &filename[8];
418 else
419 path = filename;
420
421 fd = gzopen(filename, mode);
422 return((void *) fd);
423}
424
425/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000426 * xmlGzfileRead:
427 * @context: the I/O context
428 * @buffer: where to drop data
429 * @len: number of bytes to write
430 *
431 * Read @len bytes to @buffer from the compressed I/O channel.
432 *
433 * Returns the number of bytes written
434 */
435int
436xmlGzfileRead (void * context, char * buffer, int len) {
437 return(gzread((gzFile) context, &buffer[0], len));
438}
439
440/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000441 * xmlGzfileWrite:
442 * @context: the I/O context
443 * @buffer: where to drop data
444 * @len: number of bytes to write
445 *
446 * Write @len bytes from @buffer to the compressed I/O channel.
447 *
448 * Returns the number of bytes written
449 */
450int
451xmlGzfileWrite (void * context, const char * buffer, int len) {
452 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
453}
454
455/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000456 * xmlGzfileClose:
457 * @context: the I/O context
458 *
459 * Close a compressed I/O channel
460 */
461void
462xmlGzfileClose (void * context) {
463 gzclose((gzFile) context);
464}
465#endif /* HAVE_ZLIB_H */
466
467#ifdef LIBXML_HTTP_ENABLED
468/************************************************************************
469 * *
470 * I/O for HTTP file accesses *
471 * *
472 ************************************************************************/
473/**
474 * xmlIOHTTPMatch:
475 * @filename: the URI for matching
476 *
477 * check if the URI matches an HTTP one
478 *
479 * Returns 1 if matches, 0 otherwise
480 */
481int
482xmlIOHTTPMatch (const char *filename) {
483 if (!strncmp(filename, "http://", 7))
484 return(1);
485 return(0);
486}
487
488/**
489 * xmlIOHTTPOpen:
490 * @filename: the URI for matching
491 *
492 * open an HTTP I/O channel
493 *
494 * Returns an I/O context or NULL in case of error
495 */
496void *
497xmlIOHTTPOpen (const char *filename) {
498 return(xmlNanoHTTPOpen(filename, NULL));
499}
500
501/**
502 * xmlIOHTTPRead:
503 * @context: the I/O context
504 * @buffer: where to drop data
505 * @len: number of bytes to write
506 *
507 * Read @len bytes to @buffer from the I/O channel.
508 *
509 * Returns the number of bytes written
510 */
511int
512xmlIOHTTPRead(void * context, char * buffer, int len) {
513 return(xmlNanoHTTPRead(context, &buffer[0], len));
514}
515
516/**
517 * xmlIOHTTPClose:
518 * @context: the I/O context
519 *
520 * Close an HTTP I/O channel
521 */
522void
523xmlIOHTTPClose (void * context) {
524 xmlNanoHTTPClose(context);
525}
526#endif /* LIBXML_HTTP_ENABLED */
527
528#ifdef LIBXML_FTP_ENABLED
529/************************************************************************
530 * *
531 * I/O for FTP file accesses *
532 * *
533 ************************************************************************/
534/**
535 * xmlIOFTPMatch:
536 * @filename: the URI for matching
537 *
538 * check if the URI matches an FTP one
539 *
540 * Returns 1 if matches, 0 otherwise
541 */
542int
543xmlIOFTPMatch (const char *filename) {
544 if (!strncmp(filename, "ftp://", 6))
545 return(1);
546 return(0);
547}
548
549/**
550 * xmlIOFTPOpen:
551 * @filename: the URI for matching
552 *
553 * open an FTP I/O channel
554 *
555 * Returns an I/O context or NULL in case of error
556 */
557void *
558xmlIOFTPOpen (const char *filename) {
559 return(xmlNanoFTPOpen(filename));
560}
561
562/**
563 * xmlIOFTPRead:
564 * @context: the I/O context
565 * @buffer: where to drop data
566 * @len: number of bytes to write
567 *
568 * Read @len bytes to @buffer from the I/O channel.
569 *
570 * Returns the number of bytes written
571 */
572int
573xmlIOFTPRead(void * context, char * buffer, int len) {
574 return(xmlNanoFTPRead(context, &buffer[0], len));
575}
576
577/**
578 * xmlIOFTPClose:
579 * @context: the I/O context
580 *
581 * Close an FTP I/O channel
582 */
583void
584xmlIOFTPClose (void * context) {
585 xmlNanoFTPClose(context);
586}
587#endif /* LIBXML_FTP_ENABLED */
588
589
590/**
591 * xmlRegisterInputCallbacks:
592 * @match: the xmlInputMatchCallback
593 * @open: the xmlInputOpenCallback
594 * @read: the xmlInputReadCallback
595 * @close: the xmlInputCloseCallback
596 *
597 * Register a new set of I/O callback for handling parser input.
598 *
599 * Returns the registered handler number or -1 in case of error
600 */
601int
602xmlRegisterInputCallbacks(xmlInputMatchCallback match,
603 xmlInputOpenCallback open, xmlInputReadCallback read,
604 xmlInputCloseCallback close) {
605 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
606 return(-1);
607 }
608 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match;
609 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open;
610 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read;
611 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close;
612 return(xmlInputCallbackNr++);
613}
614
615/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000616 * xmlRegisterOutputCallbacks:
617 * @match: the xmlOutputMatchCallback
618 * @open: the xmlOutputOpenCallback
619 * @write: the xmlOutputWriteCallback
620 * @close: the xmlOutputCloseCallback
621 *
622 * Register a new set of I/O callback for handling output.
623 *
624 * Returns the registered handler number or -1 in case of error
625 */
626int
627xmlRegisterOutputCallbacks(xmlOutputMatchCallback match,
628 xmlOutputOpenCallback open, xmlOutputWriteCallback write,
629 xmlOutputCloseCallback close) {
630 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
631 return(-1);
632 }
633 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = match;
634 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = open;
635 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = write;
636 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = close;
637 return(xmlOutputCallbackNr++);
638}
639
640/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000641 * xmlRegisterDefaultInputCallbacks:
642 *
643 * Registers the default compiled-in I/O handlers.
644 */
645void
646xmlRegisterDefaultInputCallbacks(void) {
647 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
648 xmlFileRead, xmlFileClose);
649#ifdef HAVE_ZLIB_H
650 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
651 xmlGzfileRead, xmlGzfileClose);
652#endif /* HAVE_ZLIB_H */
653
654#ifdef LIBXML_HTTP_ENABLED
655 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
656 xmlIOHTTPRead, xmlIOHTTPClose);
657#endif /* LIBXML_HTTP_ENABLED */
658
659#ifdef LIBXML_FTP_ENABLED
660 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
661 xmlIOFTPRead, xmlIOFTPClose);
662#endif /* LIBXML_FTP_ENABLED */
663}
664
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000665/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000666 * xmlRegisterDefaultOutputCallbacks:
667 *
668 * Registers the default compiled-in I/O handlers.
669 */
670void
671xmlRegisterDefaultOutputCallbacks(void) {
672 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
673 xmlFileWrite, xmlFileClose);
674/*********************************
675 No way a-priori to distinguish between gzipped files from
676 uncompressed ones except opening if existing then closing
677 and saving with same compression ratio ... a pain.
678
679#ifdef HAVE_ZLIB_H
680 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
681 xmlGzfileWrite, xmlGzfileClose);
682#endif
683 No HTTP PUT support yet, patches welcome
684
685#ifdef LIBXML_HTTP_ENABLED
686 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
687 xmlIOHTTPWrite, xmlIOHTTPClose);
688#endif
689
690 Nor FTP PUT ....
691#ifdef LIBXML_FTP_ENABLED
692 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
693 xmlIOFTPWrite, xmlIOFTPClose);
694#endif
695 **********************************/
696}
697
698/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000699 * xmlAllocParserInputBuffer:
700 * @enc: the charset encoding if known
701 *
702 * Create a buffered parser input for progressive parsing
703 *
704 * Returns the new parser input or NULL
705 */
706xmlParserInputBufferPtr
707xmlAllocParserInputBuffer(xmlCharEncoding enc) {
708 xmlParserInputBufferPtr ret;
709
Daniel Veillard6454aec1999-09-02 22:04:43 +0000710 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000711 if (ret == NULL) {
712 fprintf(stderr, "xmlAllocParserInputBuffer : out of memory!\n");
713 return(NULL);
714 }
715 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
716 ret->buffer = xmlBufferCreate();
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000717 if (ret->buffer == NULL) {
718 xmlFree(ret);
719 return(NULL);
720 }
721 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000722 ret->encoder = xmlGetCharEncodingHandler(enc);
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000723 if (ret->encoder != NULL)
724 ret->raw = xmlBufferCreate();
725 else
726 ret->raw = NULL;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000727 ret->readcallback = NULL;
728 ret->closecallback = NULL;
729 ret->context = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000730
731 return(ret);
732}
733
734/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000735 * xmlAllocOutputBuffer:
736 * @encoder: the encoding converter or NULL
737 *
738 * Create a buffered parser output
739 *
740 * Returns the new parser output or NULL
741 */
742xmlOutputBufferPtr
743xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
744 xmlOutputBufferPtr ret;
745
746 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
747 if (ret == NULL) {
748 fprintf(stderr, "xmlAllocOutputBuffer : out of memory!\n");
749 return(NULL);
750 }
751 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
752 ret->buffer = xmlBufferCreate();
753 if (ret->buffer == NULL) {
754 xmlFree(ret);
755 return(NULL);
756 }
757 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
758 ret->encoder = encoder;
759 if (encoder != NULL) {
760 ret->conv = xmlBufferCreateSize(4000);
761 /*
762 * This call is designed to initiate the encoder state
763 */
764 xmlCharEncOutFunc(encoder, ret->conv, NULL);
765 } else
766 ret->conv = NULL;
767 ret->writecallback = NULL;
768 ret->closecallback = NULL;
769 ret->context = NULL;
770 ret->written = 0;
771
772 return(ret);
773}
774
775/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000776 * xmlFreeParserInputBuffer:
777 * @in: a buffered parser input
778 *
779 * Free up the memory used by a buffered parser input
780 */
781void
782xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000783 if (in->raw) {
784 xmlBufferFree(in->raw);
785 in->raw = NULL;
786 }
787 if (in->encoder != NULL) {
788 xmlCharEncCloseFunc(in->encoder);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000789 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000790 if (in->closecallback != NULL) {
791 in->closecallback(in->context);
792 }
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000793 if (in->buffer != NULL) {
794 xmlBufferFree(in->buffer);
795 in->buffer = NULL;
796 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000797
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000798 memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000799 xmlFree(in);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000800}
801
802/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000803 * xmlOutputBufferClose:
804 * @out: a buffered output
805 *
806 * flushes and close the output I/O channel
807 * and free up all the associated resources
808 *
809 * Returns the number of byte written or -1 in case of error.
810 */
811int
812xmlOutputBufferClose(xmlOutputBufferPtr out) {
813 int written;
814
815 if (out == NULL)
816 return(-1);
817 xmlOutputBufferFlush(out);
818 if (out->closecallback != NULL) {
819 out->closecallback(out->context);
820 }
821 written = out->written;
822 if (out->conv) {
823 xmlBufferFree(out->conv);
824 out->conv = NULL;
825 }
826 if (out->encoder != NULL) {
827 xmlCharEncCloseFunc(out->encoder);
828 }
829 if (out->buffer != NULL) {
830 xmlBufferFree(out->buffer);
831 out->buffer = NULL;
832 }
833
834 memset(out, 0xbe, (size_t) sizeof(xmlOutputBuffer));
835 xmlFree(out);
836 return(written);
837}
838
839/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000840 * xmlParserInputBufferCreateFilename:
Daniel Veillard5d211f42000-04-07 17:00:24 +0000841 * @URI: a C string containing the URI or filename
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000842 * @enc: the charset encoding if known
843 *
844 * Create a buffered parser input for the progressive parsing of a file
845 * If filename is "-' then we use stdin as the input.
846 * Automatic support for ZLIB/Compress compressed document is provided
847 * by default if found at compile-time.
Daniel Veillardcf461992000-03-14 18:30:20 +0000848 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000849 *
850 * Returns the new parser input or NULL
851 */
852xmlParserInputBufferPtr
Daniel Veillard5d211f42000-04-07 17:00:24 +0000853xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000854 xmlParserInputBufferPtr ret;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000855 int i;
856 void *context = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000857
Daniel Veillard5d211f42000-04-07 17:00:24 +0000858 if (xmlInputCallbackInitialized == 0)
859 xmlRegisterDefaultInputCallbacks();
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000860
Daniel Veillard5d211f42000-04-07 17:00:24 +0000861 if (URI == NULL) return(NULL);
862
863 /*
864 * Try to find one of the input accept method accepting taht scheme
865 * Go in reverse to give precedence to user defined handlers.
866 */
867 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
868 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
869 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
870 context = xmlInputCallbackTable[i].opencallback(URI);
871 if (context != NULL)
872 break;
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000873 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000874 }
875 if (context == NULL) {
876#ifdef DEBUG_INPUT
877 fprintf(stderr, "No input filter matching \"%s\"\n", URI);
Daniel Veillardda07c342000-01-25 18:31:22 +0000878#endif
Daniel Veillard5d211f42000-04-07 17:00:24 +0000879 return(NULL);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000880 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000881
Daniel Veillardcf461992000-03-14 18:30:20 +0000882 /*
883 * Allocate the Input buffer front-end.
884 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000885 ret = xmlAllocParserInputBuffer(enc);
886 if (ret != NULL) {
Daniel Veillard5d211f42000-04-07 17:00:24 +0000887 ret->context = context;
888 ret->readcallback = xmlInputCallbackTable[i].readcallback;
889 ret->closecallback = xmlInputCallbackTable[i].closecallback;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000890 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000891 return(ret);
892}
893
894/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000895 * xmlOutputBufferCreateFilename:
896 * @URI: a C string containing the URI or filename
897 * @encoder: the encoding converter or NULL
898 * @compression: the compression ration (0 none, 9 max).
899 *
900 * Create a buffered output for the progressive saving of a file
901 * If filename is "-' then we use stdout as the output.
902 * Automatic support for ZLIB/Compress compressed document is provided
903 * by default if found at compile-time.
904 * TODO: currently if compression is set, the library only support
905 * writing to a local file.
906 *
907 * Returns the new output or NULL
908 */
909xmlOutputBufferPtr
910xmlOutputBufferCreateFilename(const char *URI,
911 xmlCharEncodingHandlerPtr encoder,
912 int compression) {
913 xmlOutputBufferPtr ret;
914 int i;
915 void *context = NULL;
916
917 if (xmlOutputCallbackInitialized == 0)
918 xmlRegisterDefaultOutputCallbacks();
919
920 if (URI == NULL) return(NULL);
921
922#ifdef HAVE_ZLIB_H
923 if ((compression > 0) && (compression <= 9)) {
924 context = xmlGzfileOpenW(URI, compression);
925 if (context != NULL) {
926 ret = xmlAllocOutputBuffer(encoder);
927 if (ret != NULL) {
928 ret->context = context;
929 ret->writecallback = xmlGzfileWrite;
930 ret->closecallback = xmlGzfileClose;
931 }
932 return(ret);
933 }
934 }
935#endif
936
937 /*
938 * Try to find one of the output accept method accepting taht scheme
939 * Go in reverse to give precedence to user defined handlers.
940 */
941 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
942 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
943 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
944 context = xmlOutputCallbackTable[i].opencallback(URI);
945 if (context != NULL)
946 break;
947 }
948 }
949 if (context == NULL) {
950#ifdef DEBUG_INPUT
951 fprintf(stderr, "No output filter matching \"%s\"\n", URI);
952#endif
953 return(NULL);
954 }
955
956 /*
957 * Allocate the Output buffer front-end.
958 */
959 ret = xmlAllocOutputBuffer(encoder);
960 if (ret != NULL) {
961 ret->context = context;
962 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
963 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
964 }
965 return(ret);
966}
967
968/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000969 * xmlParserInputBufferCreateFile:
970 * @file: a FILE*
971 * @enc: the charset encoding if known
972 *
973 * Create a buffered parser input for the progressive parsing of a FILE *
974 * buffered C I/O
975 *
976 * Returns the new parser input or NULL
977 */
978xmlParserInputBufferPtr
979xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
980 xmlParserInputBufferPtr ret;
981
Daniel Veillard5d211f42000-04-07 17:00:24 +0000982 if (xmlInputCallbackInitialized == 0)
983 xmlRegisterDefaultInputCallbacks();
984
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000985 if (file == NULL) return(NULL);
986
987 ret = xmlAllocParserInputBuffer(enc);
Daniel Veillard5d211f42000-04-07 17:00:24 +0000988 if (ret != NULL) {
989 ret->context = file;
990 ret->readcallback = xmlFileRead;
991 ret->closecallback = xmlFileClose;
992 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000993
994 return(ret);
995}
996
997/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000998 * xmlOutputBufferCreateFile:
999 * @file: a FILE*
1000 * @encoder: the encoding converter or NULL
1001 *
1002 * Create a buffered output for the progressive saving to a FILE *
1003 * buffered C I/O
1004 *
1005 * Returns the new parser output or NULL
1006 */
1007xmlOutputBufferPtr
1008xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1009 xmlOutputBufferPtr ret;
1010
1011 if (xmlOutputCallbackInitialized == 0)
1012 xmlRegisterDefaultOutputCallbacks();
1013
1014 if (file == NULL) return(NULL);
1015
1016 ret = xmlAllocOutputBuffer(encoder);
1017 if (ret != NULL) {
1018 ret->context = file;
1019 ret->writecallback = xmlFileWrite;
1020 ret->closecallback = xmlFileClose;
1021 }
1022
1023 return(ret);
1024}
1025
1026/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001027 * xmlParserInputBufferCreateFd:
1028 * @fd: a file descriptor number
1029 * @enc: the charset encoding if known
1030 *
1031 * Create a buffered parser input for the progressive parsing for the input
1032 * from a file descriptor
1033 *
1034 * Returns the new parser input or NULL
1035 */
1036xmlParserInputBufferPtr
1037xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1038 xmlParserInputBufferPtr ret;
1039
1040 if (fd < 0) return(NULL);
1041
1042 ret = xmlAllocParserInputBuffer(enc);
Daniel Veillard5d211f42000-04-07 17:00:24 +00001043 if (ret != NULL) {
1044 ret->context = (void *) fd;
1045 ret->readcallback = xmlFdRead;
1046 ret->closecallback = xmlFdClose;
1047 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001048
1049 return(ret);
1050}
1051
1052/**
Daniel Veillard46e370e2000-07-21 20:32:03 +00001053 * xmlParserInputBufferCreateMem:
1054 * @mem: the memory input
1055 * @size: the length of the memory block
1056 * @enc: the charset encoding if known
1057 *
1058 * Create a buffered parser input for the progressive parsing for the input
1059 * from a file descriptor
1060 *
1061 * Returns the new parser input or NULL
1062 */
1063xmlParserInputBufferPtr
1064xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1065 xmlParserInputBufferPtr ret;
1066
1067 if (size <= 0) return(NULL);
1068 if (mem == NULL) return(NULL);
1069
1070 ret = xmlAllocParserInputBuffer(enc);
1071 if (ret != NULL) {
1072 ret->context = (void *) mem;
1073 ret->readcallback = (xmlInputReadCallback) xmlNop;
1074 ret->closecallback = NULL;
1075 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1076 }
1077
1078 return(ret);
1079}
1080
1081/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001082 * xmlOutputBufferCreateFd:
1083 * @fd: a file descriptor number
1084 * @encoder: the encoding converter or NULL
1085 *
1086 * Create a buffered output for the progressive saving
1087 * to a file descriptor
1088 *
1089 * Returns the new parser output or NULL
1090 */
1091xmlOutputBufferPtr
1092xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1093 xmlOutputBufferPtr ret;
1094
1095 if (fd < 0) return(NULL);
1096
1097 ret = xmlAllocOutputBuffer(encoder);
1098 if (ret != NULL) {
1099 ret->context = (void *) fd;
1100 ret->writecallback = xmlFdWrite;
1101 ret->closecallback = xmlFdClose;
1102 }
1103
1104 return(ret);
1105}
1106
1107/**
Daniel Veillard5e873c42000-04-12 13:27:38 +00001108 * xmlParserInputBufferCreateIO:
1109 * @ioread: an I/O read function
1110 * @ioclose: an I/O close function
1111 * @ioctx: an I/O handler
1112 * @enc: the charset encoding if known
1113 *
1114 * Create a buffered parser input for the progressive parsing for the input
Daniel Veillardbe803962000-06-28 23:40:59 +00001115 * from an I/O handler
Daniel Veillard5e873c42000-04-12 13:27:38 +00001116 *
1117 * Returns the new parser input or NULL
1118 */
1119xmlParserInputBufferPtr
1120xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1121 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1122 xmlParserInputBufferPtr ret;
1123
1124 if (ioread == NULL) return(NULL);
1125
1126 ret = xmlAllocParserInputBuffer(enc);
1127 if (ret != NULL) {
1128 ret->context = (void *) ioctx;
1129 ret->readcallback = ioread;
1130 ret->closecallback = ioclose;
1131 }
1132
1133 return(ret);
1134}
1135
1136/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001137 * xmlOutputBufferCreateIO:
1138 * @iowrite: an I/O write function
1139 * @ioclose: an I/O close function
1140 * @ioctx: an I/O handler
1141 * @enc: the charset encoding if known
1142 *
1143 * Create a buffered output for the progressive saving
1144 * to an I/O handler
1145 *
1146 * Returns the new parser output or NULL
1147 */
1148xmlOutputBufferPtr
1149xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1150 xmlOutputCloseCallback ioclose, void *ioctx,
1151 xmlCharEncodingHandlerPtr encoder) {
1152 xmlOutputBufferPtr ret;
1153
1154 if (iowrite == NULL) return(NULL);
1155
1156 ret = xmlAllocOutputBuffer(encoder);
1157 if (ret != NULL) {
1158 ret->context = (void *) ioctx;
1159 ret->writecallback = iowrite;
1160 ret->closecallback = ioclose;
1161 }
1162
1163 return(ret);
1164}
1165
1166/**
Daniel Veillard7f858501999-11-17 17:32:38 +00001167 * xmlParserInputBufferPush:
1168 * @in: a buffered parser input
Daniel Veillard7f858501999-11-17 17:32:38 +00001169 * @len: the size in bytes of the array.
Daniel Veillardbe803962000-06-28 23:40:59 +00001170 * @buf: an char array
Daniel Veillard7f858501999-11-17 17:32:38 +00001171 *
1172 * Push the content of the arry in the input buffer
1173 * This routine handle the I18N transcoding to internal UTF-8
1174 * This is used when operating the parser in progressive (push) mode.
1175 *
1176 * Returns the number of chars read and stored in the buffer, or -1
1177 * in case of error.
1178 */
1179int
Daniel Veillarda819dac1999-11-24 18:04:22 +00001180xmlParserInputBufferPush(xmlParserInputBufferPtr in, int len, const char *buf) {
Daniel Veillard7f858501999-11-17 17:32:38 +00001181 int nbchars = 0;
1182
1183 if (len < 0) return(0);
1184 if (in->encoder != NULL) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001185 /*
1186 * Store the data in the incoming raw buffer
Daniel Veillard7f858501999-11-17 17:32:38 +00001187 */
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001188 if (in->raw == NULL) {
1189 in->raw = xmlBufferCreate();
1190 }
1191 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1192
1193 /*
1194 * convert as much as possible to the parser reading buffer.
1195 */
1196 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
Daniel Veillardcf461992000-03-14 18:30:20 +00001197 if (nbchars < 0) {
1198 fprintf(stderr, "xmlParserInputBufferPush: encoder error\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00001199 return(-1);
1200 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001201 } else {
1202 nbchars = len;
1203 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
Daniel Veillard7f858501999-11-17 17:32:38 +00001204 }
1205#ifdef DEBUG_INPUT
1206 fprintf(stderr, "I/O: pushed %d chars, buffer %d/%d\n",
1207 nbchars, in->buffer->use, in->buffer->size);
1208#endif
1209 return(nbchars);
1210}
1211
1212/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001213 * xmlParserInputBufferGrow:
1214 * @in: a buffered parser input
1215 * @len: indicative value of the amount of chars to read
1216 *
1217 * Grow up the content of the input buffer, the old data are preserved
1218 * This routine handle the I18N transcoding to internal UTF-8
Daniel Veillard7f858501999-11-17 17:32:38 +00001219 * This routine is used when operating the parser in normal (pull) mode
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001220 *
1221 * TODO: one should be able to remove one extra copy by copying directy
1222 * onto in->buffer or in->raw
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001223 *
1224 * Returns the number of chars read and stored in the buffer, or -1
1225 * in case of error.
1226 */
1227int
1228xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1229 char *buffer = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001230 int res = 0;
1231 int nbchars = 0;
1232 int buffree;
1233
1234 if ((len <= MINLEN) && (len != 4))
1235 len = MINLEN;
1236 buffree = in->buffer->size - in->buffer->use;
1237 if (buffree <= 0) {
1238 fprintf(stderr, "xmlParserInputBufferGrow : buffer full !\n");
1239 return(0);
1240 }
1241 if (len > buffree)
1242 len = buffree;
1243
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001244 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001245 if (buffer == NULL) {
1246 fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
1247 return(-1);
1248 }
Daniel Veillard5d211f42000-04-07 17:00:24 +00001249
1250 /*
1251 * Call the read method for this I/O type.
1252 */
1253 if (in->readcallback != NULL) {
1254 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001255 } else {
1256 fprintf(stderr, "xmlParserInputBufferGrow : no input !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001257 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001258 return(-1);
1259 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001260 if (res < 0) {
1261 perror ("read error");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001262 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001263 return(-1);
1264 }
Daniel Veillardbe803962000-06-28 23:40:59 +00001265 len = res;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001266 if (in->encoder != NULL) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001267 /*
1268 * Store the data in the incoming raw buffer
1269 */
1270 if (in->raw == NULL) {
1271 in->raw = xmlBufferCreate();
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001272 }
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001273 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
Daniel Veillardcf461992000-03-14 18:30:20 +00001274
1275 /*
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001276 * convert as much as possible to the parser reading buffer.
Daniel Veillardcf461992000-03-14 18:30:20 +00001277 */
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001278 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1279 if (nbchars < 0) {
1280 fprintf(stderr, "xmlParserInputBufferGrow: encoder error\n");
1281 return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00001282 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001283 } else {
Daniel Veillardbe803962000-06-28 23:40:59 +00001284 nbchars = len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001285 buffer[nbchars] = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001286 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001287 }
1288#ifdef DEBUG_INPUT
1289 fprintf(stderr, "I/O: read %d chars, buffer %d/%d\n",
1290 nbchars, in->buffer->use, in->buffer->size);
1291#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001292 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001293 return(nbchars);
1294}
1295
1296/**
1297 * xmlParserInputBufferRead:
1298 * @in: a buffered parser input
1299 * @len: indicative value of the amount of chars to read
1300 *
1301 * Refresh the content of the input buffer, the old data are considered
1302 * consumed
1303 * This routine handle the I18N transcoding to internal UTF-8
1304 *
1305 * Returns the number of chars read and stored in the buffer, or -1
1306 * in case of error.
1307 */
1308int
1309xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1310 /* xmlBufferEmpty(in->buffer); */
Daniel Veillard5d211f42000-04-07 17:00:24 +00001311 if (in->readcallback != NULL)
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001312 return(xmlParserInputBufferGrow(in, len));
1313 else
Daniel Veillardbe803962000-06-28 23:40:59 +00001314 return(-1);
1315}
1316
1317/**
1318 * xmlOutputBufferWrite:
1319 * @out: a buffered parser output
1320 * @len: the size in bytes of the array.
1321 * @buf: an char array
1322 *
1323 * Write the content of the array in the output I/O buffer
1324 * This routine handle the I18N transcoding from internal UTF-8
1325 * The buffer is lossless, i.e. will store in case of partial
1326 * or delayed writes.
1327 *
1328 * Returns the number of chars immediately written, or -1
1329 * in case of error.
1330 */
1331int
1332xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
1333 int nbchars = 0, ret;
1334
1335 if (len < 0) return(0);
1336
1337 /*
1338 * first handle encoding stuff.
1339 */
1340 if (out->encoder != NULL) {
1341 /*
1342 * Store the data in the incoming raw buffer
1343 */
1344 if (out->conv == NULL) {
1345 out->conv = xmlBufferCreate();
1346 }
1347 xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1348
1349 if (out->buffer->use < MINLEN)
1350 return(0);
1351
1352 /*
1353 * convert as much as possible to the parser reading buffer.
1354 */
1355 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1356 if (nbchars < 0) {
1357 fprintf(stderr, "xmlOutputBufferWrite: encoder error\n");
1358 return(-1);
1359 }
1360 nbchars = out->conv->use;
1361 } else {
1362 xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1363 nbchars = out->buffer->use;
1364 }
1365 if (nbchars < MINLEN)
1366 return(0);
1367
1368 /*
1369 * second write the stuff to the I/O channel
1370 */
1371 if (out->encoder != NULL) {
1372 ret = out->writecallback(out->context,
1373 (const char *)out->conv->content, nbchars);
1374 if (ret >= 0)
1375 xmlBufferShrink(out->conv, nbchars);
1376 } else {
1377 ret = out->writecallback(out->context,
1378 (const char *)out->buffer->content, nbchars);
1379 if (ret >= 0)
1380 xmlBufferShrink(out->buffer, nbchars);
1381 }
1382 if (ret < 0) {
1383 fprintf(stderr, "I/O: error %d writing %d bytes\n", ret, nbchars);
1384 return(ret);
1385 }
1386 out->written += ret;
1387
1388#ifdef DEBUG_INPUT
1389 fprintf(stderr, "I/O: wrote %d chars\n", ret);
1390#endif
1391 return(nbchars);
1392}
1393
1394/**
1395 * xmlOutputBufferWriteString:
1396 * @out: a buffered parser output
1397 * @str: a zero terminated C string
1398 *
1399 * Write the content of the string in the output I/O buffer
1400 * This routine handle the I18N transcoding from internal UTF-8
1401 * The buffer is lossless, i.e. will store in case of partial
1402 * or delayed writes.
1403 *
1404 * Returns the number of chars immediately written, or -1
1405 * in case of error.
1406 */
1407int
1408xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
1409 int len;
1410
1411 if (str == NULL)
1412 return(-1);
1413 len = strlen(str);
1414
1415 if (len > 0)
1416 return(xmlOutputBufferWrite(out, len, str));
1417 return(len);
1418}
1419
1420/**
1421 * xmlOutputBufferFlush:
1422 * @out: a buffered output
1423 *
1424 * flushes the output I/O channel
1425 *
1426 * Returns the number of byte written or -1 in case of error.
1427 */
1428int
1429xmlOutputBufferFlush(xmlOutputBufferPtr out) {
1430 int nbchars = 0, ret;
1431
1432 /*
1433 * first handle encoding stuff.
1434 */
1435 if ((out->conv != NULL) && (out->encoder != NULL)) {
1436 /*
1437 * convert as much as possible to the parser reading buffer.
1438 */
1439 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1440 if (nbchars < 0) {
1441 fprintf(stderr, "xmlOutputBufferWrite: encoder error\n");
1442 return(-1);
1443 }
1444 }
1445
1446 /*
1447 * second flush the stuff to the I/O channel
1448 */
1449 if ((out->conv != NULL) && (out->encoder != NULL)) {
1450 ret = out->writecallback(out->context,
1451 (const char *)out->conv->content, out->conv->use);
1452 if (ret >= 0)
1453 xmlBufferShrink(out->conv, ret);
1454 } else {
1455 ret = out->writecallback(out->context,
1456 (const char *)out->buffer->content, out->buffer->use);
1457 if (ret >= 0)
1458 xmlBufferShrink(out->buffer, ret);
1459 }
1460 if (ret < 0) {
1461 fprintf(stderr, "I/O: error %d flushing %d bytes\n", ret, nbchars);
1462 return(ret);
1463 }
1464 out->written += ret;
1465
1466#ifdef DEBUG_INPUT
1467 fprintf(stderr, "I/O: flushed %d chars\n", ret);
1468#endif
1469 return(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001470}
1471
Daniel Veillardb05deb71999-08-10 19:04:08 +00001472/*
1473 * xmlParserGetDirectory:
1474 * @filename: the path to a file
1475 *
1476 * lookup the directory for that file
1477 *
1478 * Returns a new allocated string containing the directory, or NULL.
1479 */
1480char *
1481xmlParserGetDirectory(const char *filename) {
1482 char *ret = NULL;
1483 char dir[1024];
1484 char *cur;
1485 char sep = '/';
1486
Daniel Veillard5d211f42000-04-07 17:00:24 +00001487 if (xmlInputCallbackInitialized == 0)
1488 xmlRegisterDefaultInputCallbacks();
1489
Daniel Veillardb05deb71999-08-10 19:04:08 +00001490 if (filename == NULL) return(NULL);
1491#ifdef WIN32
1492 sep = '\\';
1493#endif
1494
1495 strncpy(dir, filename, 1023);
1496 dir[1023] = 0;
1497 cur = &dir[strlen(dir)];
1498 while (cur > dir) {
1499 if (*cur == sep) break;
1500 cur --;
1501 }
1502 if (*cur == sep) {
1503 if (cur == dir) dir[1] = 0;
1504 else *cur = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001505 ret = xmlMemStrdup(dir);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001506 } else {
1507 if (getcwd(dir, 1024) != NULL) {
1508 dir[1023] = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001509 ret = xmlMemStrdup(dir);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001510 }
1511 }
1512 return(ret);
1513}
1514
Daniel Veillardb96e6431999-08-29 21:02:19 +00001515/****************************************************************
1516 * *
1517 * External entities loading *
1518 * *
1519 ****************************************************************/
1520
1521/*
1522 * xmlDefaultExternalEntityLoader:
1523 * @URL: the URL for the entity to load
1524 * @ID: the System ID for the entity to load
Daniel Veillard686d6b62000-01-03 11:08:02 +00001525 * @ctxt: the context in which the entity is called or NULL
Daniel Veillardb96e6431999-08-29 21:02:19 +00001526 *
1527 * By default we don't load external entitites, yet.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001528 *
1529 * Returns a new allocated xmlParserInputPtr, or NULL.
1530 */
1531static
1532xmlParserInputPtr
1533xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillard686d6b62000-01-03 11:08:02 +00001534 xmlParserCtxtPtr ctxt) {
1535 xmlParserInputPtr ret = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001536#ifdef DEBUG_EXTERNAL_ENTITIES
1537 fprintf(stderr, "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
1538#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001539 if (URL == NULL) {
1540 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1541 ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n",
1542 ID);
1543 return(NULL);
1544 }
1545 ret = xmlNewInputFromFile(ctxt, URL);
1546 if (ret == NULL) {
1547 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1548 ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n",
1549 URL);
1550 }
1551 return(ret);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001552}
1553
1554static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1555 xmlDefaultExternalEntityLoader;
1556
1557/*
1558 * xmlSetExternalEntityLoader:
1559 * @f: the new entity resolver function
1560 *
1561 * Changes the defaultexternal entity resolver function for the application
1562 */
1563void
1564xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1565 xmlCurrentExternalEntityLoader = f;
1566}
1567
1568/*
1569 * xmlGetExternalEntityLoader:
1570 *
1571 * Get the default external entity resolver function for the application
1572 *
1573 * Returns the xmlExternalEntityLoader function pointer
1574 */
1575xmlExternalEntityLoader
1576xmlGetExternalEntityLoader(void) {
1577 return(xmlCurrentExternalEntityLoader);
1578}
1579
1580/*
1581 * xmlLoadExternalEntity:
1582 * @URL: the URL for the entity to load
1583 * @ID: the System ID for the entity to load
Daniel Veillard686d6b62000-01-03 11:08:02 +00001584 * @ctxt: the context in which the entity is called or NULL
Daniel Veillardb96e6431999-08-29 21:02:19 +00001585 *
1586 * Load an external entity, note that the use of this function for
1587 * unparsed entities may generate problems
1588 * TODO: a more generic External entitiy API must be designed
1589 *
1590 * Returns the xmlParserInputPtr or NULL
1591 */
1592xmlParserInputPtr
1593xmlLoadExternalEntity(const char *URL, const char *ID,
Daniel Veillard686d6b62000-01-03 11:08:02 +00001594 xmlParserCtxtPtr ctxt) {
1595 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001596}
1597