blob: 31cd9133f5c28e3695c180f932ea1fafc052bb10 [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 Veillardd6d7f7b2000-10-25 19:56:55 +000043#include <libxml/xmlerror.h>
Daniel Veillarde2d034d1999-07-27 19:52:06 +000044
Daniel Veillarde2d034d1999-07-27 19:52:06 +000045/* #define VERBOSE_FAILURE */
Daniel Veillardb96e6431999-08-29 21:02:19 +000046/* #define DEBUG_EXTERNAL_ENTITIES */
Daniel Veillardbe803962000-06-28 23:40:59 +000047/* #define DEBUG_INPUT */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000048
49#ifdef DEBUG_INPUT
50#define MINLEN 40
51#else
52#define MINLEN 4000
53#endif
54
Daniel Veillard5d211f42000-04-07 17:00:24 +000055/*
56 * Input I/O callback sets
57 */
58typedef struct _xmlInputCallback {
59 xmlInputMatchCallback matchcallback;
60 xmlInputOpenCallback opencallback;
61 xmlInputReadCallback readcallback;
62 xmlInputCloseCallback closecallback;
63} xmlInputCallback;
64
65#define MAX_INPUT_CALLBACK 15
66
67xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
68int xmlInputCallbackNr = 0;
69int xmlInputCallbackInitialized = 0;
70
Daniel Veillardbe803962000-06-28 23:40:59 +000071/*
72 * Output I/O callback sets
73 */
74typedef struct _xmlOutputCallback {
75 xmlOutputMatchCallback matchcallback;
76 xmlOutputOpenCallback opencallback;
77 xmlOutputWriteCallback writecallback;
78 xmlOutputCloseCallback closecallback;
79} xmlOutputCallback;
80
81#define MAX_OUTPUT_CALLBACK 15
82
83xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
84int xmlOutputCallbackNr = 0;
85int xmlOutputCallbackInitialized = 0;
86
Daniel Veillard5d211f42000-04-07 17:00:24 +000087/************************************************************************
88 * *
89 * Standard I/O for file accesses *
90 * *
91 ************************************************************************/
92
Daniel Veillard46e370e2000-07-21 20:32:03 +000093int
94xmlNop(void) {
95 return(0);
96}
97
Daniel Veillard5d211f42000-04-07 17:00:24 +000098/**
99 * xmlFdMatch:
100 * @filename: the URI for matching
101 *
102 * input from file descriptor
103 *
104 * Returns 1 if matches, 0 otherwise
105 */
106int
107xmlFdMatch (const char *filename) {
108 return(1);
109}
110
111/**
112 * xmlFdOpen:
113 * @filename: the URI for matching
114 *
115 * input from file descriptor, supports compressed input
116 * if @filename is " " then the standard input is used
117 *
118 * Returns an I/O context or NULL in case of error
119 */
120void *
121xmlFdOpen (const char *filename) {
122 const char *path = NULL;
123 int fd;
124
125 if (!strcmp(filename, "-")) {
126 fd = 0;
127 return((void *) fd);
128 }
129
130 if (!strncmp(filename, "file://localhost", 16))
131 path = &filename[16];
132 else if (!strncmp(filename, "file:///", 8))
133 path = &filename[8];
134 else if (filename[0] == '/')
135 path = filename;
136 if (path == NULL)
137 return(NULL);
138
139#ifdef WIN32
140 fd = _open (filename, O_RDONLY | _O_BINARY);
141#else
142 fd = open (filename, O_RDONLY);
143#endif
144
145 return((void *) fd);
146}
147
148/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000149 * xmlFdOpenW:
150 * @filename: the URI for matching
151 *
152 * input from file descriptor,
153 * if @filename is "-" then the standard output is used
154 *
155 * Returns an I/O context or NULL in case of error
156 */
157void *
158xmlFdOpenW (const char *filename) {
159 const char *path = NULL;
160 int fd;
161
162 if (!strcmp(filename, "-")) {
163 fd = 1;
164 return((void *) fd);
165 }
166
167 if (!strncmp(filename, "file://localhost", 16))
168 path = &filename[16];
169 else if (!strncmp(filename, "file:///", 8))
170 path = &filename[8];
171 else if (filename[0] == '/')
172 path = filename;
173 if (path == NULL)
174 return(NULL);
175
176 fd = open (filename, O_WRONLY);
177
178 return((void *) fd);
179}
180
181/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000182 * xmlFdRead:
183 * @context: the I/O context
184 * @buffer: where to drop data
Daniel Veillardbe803962000-06-28 23:40:59 +0000185 * @len: number of bytes to read
Daniel Veillard5d211f42000-04-07 17:00:24 +0000186 *
187 * Read @len bytes to @buffer from the I/O channel.
188 *
189 * Returns the number of bytes written
190 */
191int
192xmlFdRead (void * context, char * buffer, int len) {
193 return(read((int) context, &buffer[0], len));
194}
195
196/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000197 * xmlFdWrite:
198 * @context: the I/O context
199 * @buffer: where to get data
200 * @len: number of bytes to write
201 *
202 * Write @len bytes from @buffer to the I/O channel.
203 *
204 * Returns the number of bytes written
205 */
206int
207xmlFdWrite (void * context, const char * buffer, int len) {
208 return(write((int) context, &buffer[0], len));
209}
210
211/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000212 * xmlFdClose:
213 * @context: the I/O context
214 *
215 * Close an I/O channel
216 */
217void
218xmlFdClose (void * context) {
219 close((int) context);
220}
221
222/**
223 * xmlFileMatch:
224 * @filename: the URI for matching
225 *
226 * input from FILE *
227 *
228 * Returns 1 if matches, 0 otherwise
229 */
230int
231xmlFileMatch (const char *filename) {
232 return(1);
233}
234
235/**
236 * xmlFileOpen:
237 * @filename: the URI for matching
238 *
239 * input from FILE *, supports compressed input
240 * if @filename is " " then the standard input is used
241 *
242 * Returns an I/O context or NULL in case of error
243 */
244void *
245xmlFileOpen (const char *filename) {
246 const char *path = NULL;
247 FILE *fd;
248
249 if (!strcmp(filename, "-")) {
250 fd = stdin;
251 return((void *) fd);
252 }
253
254 if (!strncmp(filename, "file://localhost", 16))
255 path = &filename[16];
256 else if (!strncmp(filename, "file:///", 8))
257 path = &filename[8];
258 else
259 path = filename;
260 if (path == NULL)
261 return(NULL);
262
263#ifdef WIN32
264 fd = fopen(path, "rb");
265#else
266 fd = fopen(path, "r");
267#endif /* WIN32 */
268 return((void *) fd);
269}
270
271/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000272 * xmlFileOpenW:
273 * @filename: the URI for matching
274 *
275 * output to from FILE *,
276 * if @filename is "-" then the standard output is used
277 *
278 * Returns an I/O context or NULL in case of error
279 */
280void *
281xmlFileOpenW (const char *filename) {
282 const char *path = NULL;
283 FILE *fd;
284
285 if (!strcmp(filename, "-")) {
286 fd = stdout;
287 return((void *) fd);
288 }
289
290 if (!strncmp(filename, "file://localhost", 16))
291 path = &filename[16];
292 else if (!strncmp(filename, "file:///", 8))
293 path = &filename[8];
294 else
295 path = filename;
296 if (path == NULL)
297 return(NULL);
298
299 fd = fopen(path, "w");
300 return((void *) fd);
301}
302
303/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000304 * xmlFileRead:
305 * @context: the I/O context
306 * @buffer: where to drop data
307 * @len: number of bytes to write
308 *
309 * Read @len bytes to @buffer from the I/O channel.
310 *
311 * Returns the number of bytes written
312 */
313int
314xmlFileRead (void * context, char * buffer, int len) {
315 return(fread(&buffer[0], 1, len, (FILE *) context));
316}
317
318/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000319 * xmlFileWrite:
320 * @context: the I/O context
321 * @buffer: where to drop data
322 * @len: number of bytes to write
323 *
324 * Write @len bytes from @buffer to the I/O channel.
325 *
326 * Returns the number of bytes written
327 */
328int
329xmlFileWrite (void * context, const char * buffer, int len) {
330 return(fwrite(&buffer[0], 1, len, (FILE *) context));
331}
332
333/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000334 * xmlFileClose:
335 * @context: the I/O context
336 *
337 * Close an I/O channel
338 */
339void
340xmlFileClose (void * context) {
341 fclose((FILE *) context);
342}
343
Daniel Veillard52afe802000-10-22 16:56:02 +0000344/**
345 * xmlFileFlush:
346 * @context: the I/O context
347 *
348 * Flush an I/O channel
349 */
350void
351xmlFileFlush (void * context) {
352 fflush((FILE *) context);
353}
354
Daniel Veillard5d211f42000-04-07 17:00:24 +0000355#ifdef HAVE_ZLIB_H
356/************************************************************************
357 * *
358 * I/O for compressed file accesses *
359 * *
360 ************************************************************************/
361/**
362 * xmlGzfileMatch:
363 * @filename: the URI for matching
364 *
365 * input from compressed file test
366 *
367 * Returns 1 if matches, 0 otherwise
368 */
369int
370xmlGzfileMatch (const char *filename) {
371 return(1);
372}
373
374/**
375 * xmlGzfileOpen:
376 * @filename: the URI for matching
377 *
378 * input from compressed file open
379 * if @filename is " " then the standard input is used
380 *
381 * Returns an I/O context or NULL in case of error
382 */
383void *
384xmlGzfileOpen (const char *filename) {
385 const char *path = NULL;
386 gzFile fd;
387
388 if (!strcmp(filename, "-")) {
Daniel Veillard2f971a22000-10-12 23:26:32 +0000389 fd = gzdopen(fileno(stdin), "rb");
Daniel Veillard5d211f42000-04-07 17:00:24 +0000390 return((void *) fd);
391 }
392
393 if (!strncmp(filename, "file://localhost", 16))
394 path = &filename[16];
395 else if (!strncmp(filename, "file:///", 8))
396 path = &filename[8];
397 else
398 path = filename;
399
Daniel Veillard2f971a22000-10-12 23:26:32 +0000400 fd = gzopen(filename, "rb");
Daniel Veillard5d211f42000-04-07 17:00:24 +0000401 return((void *) fd);
402}
403
404/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000405 * xmlGzfileOpenW:
406 * @filename: the URI for matching
407 * @compression: the compression factor (0 - 9 included)
408 *
409 * input from compressed file open
410 * if @filename is " " then the standard input is used
411 *
412 * Returns an I/O context or NULL in case of error
413 */
414void *
415xmlGzfileOpenW (const char *filename, int compression) {
416 const char *path = NULL;
417 char mode[15];
418 gzFile fd;
419
Daniel Veillard2f971a22000-10-12 23:26:32 +0000420 sprintf(mode, "wb%d", compression);
Daniel Veillardbe803962000-06-28 23:40:59 +0000421 if (!strcmp(filename, "-")) {
422 fd = gzdopen(1, mode);
423 return((void *) fd);
424 }
425
426 if (!strncmp(filename, "file://localhost", 16))
427 path = &filename[16];
428 else if (!strncmp(filename, "file:///", 8))
429 path = &filename[8];
430 else
431 path = filename;
432
433 fd = gzopen(filename, mode);
434 return((void *) fd);
435}
436
437/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000438 * xmlGzfileRead:
439 * @context: the I/O context
440 * @buffer: where to drop data
441 * @len: number of bytes to write
442 *
443 * Read @len bytes to @buffer from the compressed I/O channel.
444 *
445 * Returns the number of bytes written
446 */
447int
448xmlGzfileRead (void * context, char * buffer, int len) {
449 return(gzread((gzFile) context, &buffer[0], len));
450}
451
452/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000453 * xmlGzfileWrite:
454 * @context: the I/O context
455 * @buffer: where to drop data
456 * @len: number of bytes to write
457 *
458 * Write @len bytes from @buffer to the compressed I/O channel.
459 *
460 * Returns the number of bytes written
461 */
462int
463xmlGzfileWrite (void * context, const char * buffer, int len) {
464 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
465}
466
467/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000468 * xmlGzfileClose:
469 * @context: the I/O context
470 *
471 * Close a compressed I/O channel
472 */
473void
474xmlGzfileClose (void * context) {
475 gzclose((gzFile) context);
476}
477#endif /* HAVE_ZLIB_H */
478
479#ifdef LIBXML_HTTP_ENABLED
480/************************************************************************
481 * *
482 * I/O for HTTP file accesses *
483 * *
484 ************************************************************************/
485/**
486 * xmlIOHTTPMatch:
487 * @filename: the URI for matching
488 *
489 * check if the URI matches an HTTP one
490 *
491 * Returns 1 if matches, 0 otherwise
492 */
493int
494xmlIOHTTPMatch (const char *filename) {
495 if (!strncmp(filename, "http://", 7))
496 return(1);
497 return(0);
498}
499
500/**
501 * xmlIOHTTPOpen:
502 * @filename: the URI for matching
503 *
504 * open an HTTP I/O channel
505 *
506 * Returns an I/O context or NULL in case of error
507 */
508void *
509xmlIOHTTPOpen (const char *filename) {
510 return(xmlNanoHTTPOpen(filename, NULL));
511}
512
513/**
514 * xmlIOHTTPRead:
515 * @context: the I/O context
516 * @buffer: where to drop data
517 * @len: number of bytes to write
518 *
519 * Read @len bytes to @buffer from the I/O channel.
520 *
521 * Returns the number of bytes written
522 */
523int
524xmlIOHTTPRead(void * context, char * buffer, int len) {
525 return(xmlNanoHTTPRead(context, &buffer[0], len));
526}
527
528/**
529 * xmlIOHTTPClose:
530 * @context: the I/O context
531 *
532 * Close an HTTP I/O channel
533 */
534void
535xmlIOHTTPClose (void * context) {
536 xmlNanoHTTPClose(context);
537}
538#endif /* LIBXML_HTTP_ENABLED */
539
540#ifdef LIBXML_FTP_ENABLED
541/************************************************************************
542 * *
543 * I/O for FTP file accesses *
544 * *
545 ************************************************************************/
546/**
547 * xmlIOFTPMatch:
548 * @filename: the URI for matching
549 *
550 * check if the URI matches an FTP one
551 *
552 * Returns 1 if matches, 0 otherwise
553 */
554int
555xmlIOFTPMatch (const char *filename) {
556 if (!strncmp(filename, "ftp://", 6))
557 return(1);
558 return(0);
559}
560
561/**
562 * xmlIOFTPOpen:
563 * @filename: the URI for matching
564 *
565 * open an FTP I/O channel
566 *
567 * Returns an I/O context or NULL in case of error
568 */
569void *
570xmlIOFTPOpen (const char *filename) {
571 return(xmlNanoFTPOpen(filename));
572}
573
574/**
575 * xmlIOFTPRead:
576 * @context: the I/O context
577 * @buffer: where to drop data
578 * @len: number of bytes to write
579 *
580 * Read @len bytes to @buffer from the I/O channel.
581 *
582 * Returns the number of bytes written
583 */
584int
585xmlIOFTPRead(void * context, char * buffer, int len) {
586 return(xmlNanoFTPRead(context, &buffer[0], len));
587}
588
589/**
590 * xmlIOFTPClose:
591 * @context: the I/O context
592 *
593 * Close an FTP I/O channel
594 */
595void
596xmlIOFTPClose (void * context) {
597 xmlNanoFTPClose(context);
598}
599#endif /* LIBXML_FTP_ENABLED */
600
601
602/**
603 * xmlRegisterInputCallbacks:
604 * @match: the xmlInputMatchCallback
605 * @open: the xmlInputOpenCallback
606 * @read: the xmlInputReadCallback
607 * @close: the xmlInputCloseCallback
608 *
609 * Register a new set of I/O callback for handling parser input.
610 *
611 * Returns the registered handler number or -1 in case of error
612 */
613int
614xmlRegisterInputCallbacks(xmlInputMatchCallback match,
615 xmlInputOpenCallback open, xmlInputReadCallback read,
616 xmlInputCloseCallback close) {
617 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
618 return(-1);
619 }
620 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match;
621 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open;
622 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read;
623 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close;
624 return(xmlInputCallbackNr++);
625}
626
627/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000628 * xmlRegisterOutputCallbacks:
629 * @match: the xmlOutputMatchCallback
630 * @open: the xmlOutputOpenCallback
631 * @write: the xmlOutputWriteCallback
632 * @close: the xmlOutputCloseCallback
633 *
634 * Register a new set of I/O callback for handling output.
635 *
636 * Returns the registered handler number or -1 in case of error
637 */
638int
639xmlRegisterOutputCallbacks(xmlOutputMatchCallback match,
640 xmlOutputOpenCallback open, xmlOutputWriteCallback write,
641 xmlOutputCloseCallback close) {
642 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
643 return(-1);
644 }
645 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = match;
646 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = open;
647 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = write;
648 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = close;
649 return(xmlOutputCallbackNr++);
650}
651
652/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000653 * xmlRegisterDefaultInputCallbacks:
654 *
655 * Registers the default compiled-in I/O handlers.
656 */
657void
658xmlRegisterDefaultInputCallbacks(void) {
Daniel Veillard7cfce322000-10-04 12:40:27 +0000659 if (xmlInputCallbackInitialized)
660 return;
661
Daniel Veillard5d211f42000-04-07 17:00:24 +0000662 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
663 xmlFileRead, xmlFileClose);
664#ifdef HAVE_ZLIB_H
665 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
666 xmlGzfileRead, xmlGzfileClose);
667#endif /* HAVE_ZLIB_H */
668
669#ifdef LIBXML_HTTP_ENABLED
670 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
671 xmlIOHTTPRead, xmlIOHTTPClose);
672#endif /* LIBXML_HTTP_ENABLED */
673
674#ifdef LIBXML_FTP_ENABLED
675 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
676 xmlIOFTPRead, xmlIOFTPClose);
677#endif /* LIBXML_FTP_ENABLED */
Daniel Veillard7cfce322000-10-04 12:40:27 +0000678 xmlInputCallbackInitialized = 1;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000679}
680
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000681/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000682 * xmlRegisterDefaultOutputCallbacks:
683 *
684 * Registers the default compiled-in I/O handlers.
685 */
686void
687xmlRegisterDefaultOutputCallbacks(void) {
Daniel Veillard7cfce322000-10-04 12:40:27 +0000688 if (xmlOutputCallbackInitialized)
689 return;
690
Daniel Veillardbe803962000-06-28 23:40:59 +0000691 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
692 xmlFileWrite, xmlFileClose);
693/*********************************
694 No way a-priori to distinguish between gzipped files from
695 uncompressed ones except opening if existing then closing
696 and saving with same compression ratio ... a pain.
697
698#ifdef HAVE_ZLIB_H
699 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
700 xmlGzfileWrite, xmlGzfileClose);
701#endif
702 No HTTP PUT support yet, patches welcome
703
704#ifdef LIBXML_HTTP_ENABLED
705 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
706 xmlIOHTTPWrite, xmlIOHTTPClose);
707#endif
708
709 Nor FTP PUT ....
710#ifdef LIBXML_FTP_ENABLED
711 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
712 xmlIOFTPWrite, xmlIOFTPClose);
713#endif
714 **********************************/
Daniel Veillard7cfce322000-10-04 12:40:27 +0000715 xmlOutputCallbackInitialized = 1;
Daniel Veillardbe803962000-06-28 23:40:59 +0000716}
717
718/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000719 * xmlAllocParserInputBuffer:
720 * @enc: the charset encoding if known
721 *
722 * Create a buffered parser input for progressive parsing
723 *
724 * Returns the new parser input or NULL
725 */
726xmlParserInputBufferPtr
727xmlAllocParserInputBuffer(xmlCharEncoding enc) {
728 xmlParserInputBufferPtr ret;
729
Daniel Veillard6454aec1999-09-02 22:04:43 +0000730 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000731 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000732 xmlGenericError(xmlGenericErrorContext,
733 "xmlAllocParserInputBuffer : out of memory!\n");
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000734 return(NULL);
735 }
736 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
737 ret->buffer = xmlBufferCreate();
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000738 if (ret->buffer == NULL) {
739 xmlFree(ret);
740 return(NULL);
741 }
742 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000743 ret->encoder = xmlGetCharEncodingHandler(enc);
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000744 if (ret->encoder != NULL)
745 ret->raw = xmlBufferCreate();
746 else
747 ret->raw = NULL;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000748 ret->readcallback = NULL;
749 ret->closecallback = NULL;
750 ret->context = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000751
752 return(ret);
753}
754
755/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000756 * xmlAllocOutputBuffer:
757 * @encoder: the encoding converter or NULL
758 *
759 * Create a buffered parser output
760 *
761 * Returns the new parser output or NULL
762 */
763xmlOutputBufferPtr
764xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
765 xmlOutputBufferPtr ret;
766
767 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
768 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000769 xmlGenericError(xmlGenericErrorContext,
770 "xmlAllocOutputBuffer : out of memory!\n");
Daniel Veillardbe803962000-06-28 23:40:59 +0000771 return(NULL);
772 }
773 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
774 ret->buffer = xmlBufferCreate();
775 if (ret->buffer == NULL) {
776 xmlFree(ret);
777 return(NULL);
778 }
779 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
780 ret->encoder = encoder;
781 if (encoder != NULL) {
782 ret->conv = xmlBufferCreateSize(4000);
783 /*
784 * This call is designed to initiate the encoder state
785 */
786 xmlCharEncOutFunc(encoder, ret->conv, NULL);
787 } else
788 ret->conv = NULL;
789 ret->writecallback = NULL;
790 ret->closecallback = NULL;
791 ret->context = NULL;
792 ret->written = 0;
793
794 return(ret);
795}
796
797/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000798 * xmlFreeParserInputBuffer:
799 * @in: a buffered parser input
800 *
801 * Free up the memory used by a buffered parser input
802 */
803void
804xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000805 if (in->raw) {
806 xmlBufferFree(in->raw);
807 in->raw = NULL;
808 }
809 if (in->encoder != NULL) {
810 xmlCharEncCloseFunc(in->encoder);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000811 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000812 if (in->closecallback != NULL) {
813 in->closecallback(in->context);
814 }
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000815 if (in->buffer != NULL) {
816 xmlBufferFree(in->buffer);
817 in->buffer = NULL;
818 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000819
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000820 memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000821 xmlFree(in);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000822}
823
824/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000825 * xmlOutputBufferClose:
826 * @out: a buffered output
827 *
828 * flushes and close the output I/O channel
829 * and free up all the associated resources
830 *
831 * Returns the number of byte written or -1 in case of error.
832 */
833int
834xmlOutputBufferClose(xmlOutputBufferPtr out) {
835 int written;
836
837 if (out == NULL)
838 return(-1);
839 xmlOutputBufferFlush(out);
840 if (out->closecallback != NULL) {
841 out->closecallback(out->context);
842 }
843 written = out->written;
844 if (out->conv) {
845 xmlBufferFree(out->conv);
846 out->conv = NULL;
847 }
848 if (out->encoder != NULL) {
849 xmlCharEncCloseFunc(out->encoder);
850 }
851 if (out->buffer != NULL) {
852 xmlBufferFree(out->buffer);
853 out->buffer = NULL;
854 }
855
856 memset(out, 0xbe, (size_t) sizeof(xmlOutputBuffer));
857 xmlFree(out);
858 return(written);
859}
860
861/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000862 * xmlParserInputBufferCreateFilename:
Daniel Veillard5d211f42000-04-07 17:00:24 +0000863 * @URI: a C string containing the URI or filename
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000864 * @enc: the charset encoding if known
865 *
866 * Create a buffered parser input for the progressive parsing of a file
867 * If filename is "-' then we use stdin as the input.
868 * Automatic support for ZLIB/Compress compressed document is provided
869 * by default if found at compile-time.
Daniel Veillardcf461992000-03-14 18:30:20 +0000870 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000871 *
872 * Returns the new parser input or NULL
873 */
874xmlParserInputBufferPtr
Daniel Veillard5d211f42000-04-07 17:00:24 +0000875xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000876 xmlParserInputBufferPtr ret;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000877 int i;
878 void *context = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000879
Daniel Veillard5d211f42000-04-07 17:00:24 +0000880 if (xmlInputCallbackInitialized == 0)
881 xmlRegisterDefaultInputCallbacks();
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000882
Daniel Veillard5d211f42000-04-07 17:00:24 +0000883 if (URI == NULL) return(NULL);
884
885 /*
886 * Try to find one of the input accept method accepting taht scheme
887 * Go in reverse to give precedence to user defined handlers.
888 */
889 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
890 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
891 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
892 context = xmlInputCallbackTable[i].opencallback(URI);
893 if (context != NULL)
894 break;
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000895 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000896 }
897 if (context == NULL) {
Daniel Veillard5d211f42000-04-07 17:00:24 +0000898 return(NULL);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000899 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000900
Daniel Veillardcf461992000-03-14 18:30:20 +0000901 /*
902 * Allocate the Input buffer front-end.
903 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000904 ret = xmlAllocParserInputBuffer(enc);
905 if (ret != NULL) {
Daniel Veillard5d211f42000-04-07 17:00:24 +0000906 ret->context = context;
907 ret->readcallback = xmlInputCallbackTable[i].readcallback;
908 ret->closecallback = xmlInputCallbackTable[i].closecallback;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000909 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000910 return(ret);
911}
912
913/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000914 * xmlOutputBufferCreateFilename:
915 * @URI: a C string containing the URI or filename
916 * @encoder: the encoding converter or NULL
917 * @compression: the compression ration (0 none, 9 max).
918 *
919 * Create a buffered output for the progressive saving of a file
920 * If filename is "-' then we use stdout as the output.
921 * Automatic support for ZLIB/Compress compressed document is provided
922 * by default if found at compile-time.
923 * TODO: currently if compression is set, the library only support
924 * writing to a local file.
925 *
926 * Returns the new output or NULL
927 */
928xmlOutputBufferPtr
929xmlOutputBufferCreateFilename(const char *URI,
930 xmlCharEncodingHandlerPtr encoder,
931 int compression) {
932 xmlOutputBufferPtr ret;
933 int i;
934 void *context = NULL;
935
936 if (xmlOutputCallbackInitialized == 0)
937 xmlRegisterDefaultOutputCallbacks();
938
939 if (URI == NULL) return(NULL);
940
941#ifdef HAVE_ZLIB_H
942 if ((compression > 0) && (compression <= 9)) {
943 context = xmlGzfileOpenW(URI, compression);
944 if (context != NULL) {
945 ret = xmlAllocOutputBuffer(encoder);
946 if (ret != NULL) {
947 ret->context = context;
948 ret->writecallback = xmlGzfileWrite;
949 ret->closecallback = xmlGzfileClose;
950 }
951 return(ret);
952 }
953 }
954#endif
955
956 /*
957 * Try to find one of the output accept method accepting taht scheme
958 * Go in reverse to give precedence to user defined handlers.
959 */
960 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
961 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
962 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
963 context = xmlOutputCallbackTable[i].opencallback(URI);
964 if (context != NULL)
965 break;
966 }
967 }
968 if (context == NULL) {
Daniel Veillardbe803962000-06-28 23:40:59 +0000969 return(NULL);
970 }
971
972 /*
973 * Allocate the Output buffer front-end.
974 */
975 ret = xmlAllocOutputBuffer(encoder);
976 if (ret != NULL) {
977 ret->context = context;
978 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
979 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
980 }
981 return(ret);
982}
983
984/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000985 * xmlParserInputBufferCreateFile:
986 * @file: a FILE*
987 * @enc: the charset encoding if known
988 *
989 * Create a buffered parser input for the progressive parsing of a FILE *
990 * buffered C I/O
991 *
992 * Returns the new parser input or NULL
993 */
994xmlParserInputBufferPtr
995xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
996 xmlParserInputBufferPtr ret;
997
Daniel Veillard5d211f42000-04-07 17:00:24 +0000998 if (xmlInputCallbackInitialized == 0)
999 xmlRegisterDefaultInputCallbacks();
1000
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001001 if (file == NULL) return(NULL);
1002
1003 ret = xmlAllocParserInputBuffer(enc);
Daniel Veillard5d211f42000-04-07 17:00:24 +00001004 if (ret != NULL) {
1005 ret->context = file;
1006 ret->readcallback = xmlFileRead;
Daniel Veillard52afe802000-10-22 16:56:02 +00001007 ret->closecallback = xmlFileFlush;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001008 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001009
1010 return(ret);
1011}
1012
1013/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001014 * xmlOutputBufferCreateFile:
1015 * @file: a FILE*
1016 * @encoder: the encoding converter or NULL
1017 *
1018 * Create a buffered output for the progressive saving to a FILE *
1019 * buffered C I/O
1020 *
1021 * Returns the new parser output or NULL
1022 */
1023xmlOutputBufferPtr
1024xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1025 xmlOutputBufferPtr ret;
1026
1027 if (xmlOutputCallbackInitialized == 0)
1028 xmlRegisterDefaultOutputCallbacks();
1029
1030 if (file == NULL) return(NULL);
1031
1032 ret = xmlAllocOutputBuffer(encoder);
1033 if (ret != NULL) {
1034 ret->context = file;
1035 ret->writecallback = xmlFileWrite;
Daniel Veillard52afe802000-10-22 16:56:02 +00001036 ret->closecallback = xmlFileFlush;
Daniel Veillardbe803962000-06-28 23:40:59 +00001037 }
1038
1039 return(ret);
1040}
1041
1042/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001043 * xmlParserInputBufferCreateFd:
1044 * @fd: a file descriptor number
1045 * @enc: the charset encoding if known
1046 *
1047 * Create a buffered parser input for the progressive parsing for the input
1048 * from a file descriptor
1049 *
1050 * Returns the new parser input or NULL
1051 */
1052xmlParserInputBufferPtr
1053xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1054 xmlParserInputBufferPtr ret;
1055
1056 if (fd < 0) return(NULL);
1057
1058 ret = xmlAllocParserInputBuffer(enc);
Daniel Veillard5d211f42000-04-07 17:00:24 +00001059 if (ret != NULL) {
1060 ret->context = (void *) fd;
1061 ret->readcallback = xmlFdRead;
1062 ret->closecallback = xmlFdClose;
1063 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001064
1065 return(ret);
1066}
1067
1068/**
Daniel Veillard46e370e2000-07-21 20:32:03 +00001069 * xmlParserInputBufferCreateMem:
1070 * @mem: the memory input
1071 * @size: the length of the memory block
1072 * @enc: the charset encoding if known
1073 *
1074 * Create a buffered parser input for the progressive parsing for the input
1075 * from a file descriptor
1076 *
1077 * Returns the new parser input or NULL
1078 */
1079xmlParserInputBufferPtr
1080xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1081 xmlParserInputBufferPtr ret;
1082
1083 if (size <= 0) return(NULL);
1084 if (mem == NULL) return(NULL);
1085
1086 ret = xmlAllocParserInputBuffer(enc);
1087 if (ret != NULL) {
1088 ret->context = (void *) mem;
1089 ret->readcallback = (xmlInputReadCallback) xmlNop;
1090 ret->closecallback = NULL;
1091 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1092 }
1093
1094 return(ret);
1095}
1096
1097/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001098 * xmlOutputBufferCreateFd:
1099 * @fd: a file descriptor number
1100 * @encoder: the encoding converter or NULL
1101 *
1102 * Create a buffered output for the progressive saving
1103 * to a file descriptor
1104 *
1105 * Returns the new parser output or NULL
1106 */
1107xmlOutputBufferPtr
1108xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1109 xmlOutputBufferPtr ret;
1110
1111 if (fd < 0) return(NULL);
1112
1113 ret = xmlAllocOutputBuffer(encoder);
1114 if (ret != NULL) {
1115 ret->context = (void *) fd;
1116 ret->writecallback = xmlFdWrite;
1117 ret->closecallback = xmlFdClose;
1118 }
1119
1120 return(ret);
1121}
1122
1123/**
Daniel Veillard5e873c42000-04-12 13:27:38 +00001124 * xmlParserInputBufferCreateIO:
1125 * @ioread: an I/O read function
1126 * @ioclose: an I/O close function
1127 * @ioctx: an I/O handler
1128 * @enc: the charset encoding if known
1129 *
1130 * Create a buffered parser input for the progressive parsing for the input
Daniel Veillardbe803962000-06-28 23:40:59 +00001131 * from an I/O handler
Daniel Veillard5e873c42000-04-12 13:27:38 +00001132 *
1133 * Returns the new parser input or NULL
1134 */
1135xmlParserInputBufferPtr
1136xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1137 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1138 xmlParserInputBufferPtr ret;
1139
1140 if (ioread == NULL) return(NULL);
1141
1142 ret = xmlAllocParserInputBuffer(enc);
1143 if (ret != NULL) {
1144 ret->context = (void *) ioctx;
1145 ret->readcallback = ioread;
1146 ret->closecallback = ioclose;
1147 }
1148
1149 return(ret);
1150}
1151
1152/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001153 * xmlOutputBufferCreateIO:
1154 * @iowrite: an I/O write function
1155 * @ioclose: an I/O close function
1156 * @ioctx: an I/O handler
1157 * @enc: the charset encoding if known
1158 *
1159 * Create a buffered output for the progressive saving
1160 * to an I/O handler
1161 *
1162 * Returns the new parser output or NULL
1163 */
1164xmlOutputBufferPtr
1165xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1166 xmlOutputCloseCallback ioclose, void *ioctx,
1167 xmlCharEncodingHandlerPtr encoder) {
1168 xmlOutputBufferPtr ret;
1169
1170 if (iowrite == NULL) return(NULL);
1171
1172 ret = xmlAllocOutputBuffer(encoder);
1173 if (ret != NULL) {
1174 ret->context = (void *) ioctx;
1175 ret->writecallback = iowrite;
1176 ret->closecallback = ioclose;
1177 }
1178
1179 return(ret);
1180}
1181
1182/**
Daniel Veillard7f858501999-11-17 17:32:38 +00001183 * xmlParserInputBufferPush:
1184 * @in: a buffered parser input
Daniel Veillard7f858501999-11-17 17:32:38 +00001185 * @len: the size in bytes of the array.
Daniel Veillardbe803962000-06-28 23:40:59 +00001186 * @buf: an char array
Daniel Veillard7f858501999-11-17 17:32:38 +00001187 *
1188 * Push the content of the arry in the input buffer
1189 * This routine handle the I18N transcoding to internal UTF-8
1190 * This is used when operating the parser in progressive (push) mode.
1191 *
1192 * Returns the number of chars read and stored in the buffer, or -1
1193 * in case of error.
1194 */
1195int
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001196xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1197 int len, const char *buf) {
Daniel Veillard7f858501999-11-17 17:32:38 +00001198 int nbchars = 0;
1199
1200 if (len < 0) return(0);
1201 if (in->encoder != NULL) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001202 /*
1203 * Store the data in the incoming raw buffer
Daniel Veillard7f858501999-11-17 17:32:38 +00001204 */
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001205 if (in->raw == NULL) {
1206 in->raw = xmlBufferCreate();
1207 }
1208 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1209
1210 /*
1211 * convert as much as possible to the parser reading buffer.
1212 */
1213 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
Daniel Veillardcf461992000-03-14 18:30:20 +00001214 if (nbchars < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001215 xmlGenericError(xmlGenericErrorContext,
1216 "xmlParserInputBufferPush: encoder error\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00001217 return(-1);
1218 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001219 } else {
1220 nbchars = len;
1221 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
Daniel Veillard7f858501999-11-17 17:32:38 +00001222 }
1223#ifdef DEBUG_INPUT
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001224 xmlGenericError(xmlGenericErrorContext,
1225 "I/O: pushed %d chars, buffer %d/%d\n",
Daniel Veillard7f858501999-11-17 17:32:38 +00001226 nbchars, in->buffer->use, in->buffer->size);
1227#endif
1228 return(nbchars);
1229}
1230
1231/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001232 * xmlParserInputBufferGrow:
1233 * @in: a buffered parser input
1234 * @len: indicative value of the amount of chars to read
1235 *
1236 * Grow up the content of the input buffer, the old data are preserved
1237 * This routine handle the I18N transcoding to internal UTF-8
Daniel Veillard7f858501999-11-17 17:32:38 +00001238 * This routine is used when operating the parser in normal (pull) mode
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001239 *
1240 * TODO: one should be able to remove one extra copy by copying directy
1241 * onto in->buffer or in->raw
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001242 *
1243 * Returns the number of chars read and stored in the buffer, or -1
1244 * in case of error.
1245 */
1246int
1247xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1248 char *buffer = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001249 int res = 0;
1250 int nbchars = 0;
1251 int buffree;
1252
1253 if ((len <= MINLEN) && (len != 4))
1254 len = MINLEN;
1255 buffree = in->buffer->size - in->buffer->use;
1256 if (buffree <= 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001257 xmlGenericError(xmlGenericErrorContext,
1258 "xmlParserInputBufferGrow : buffer full !\n");
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001259 return(0);
1260 }
1261 if (len > buffree)
1262 len = buffree;
1263
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001264 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001265 if (buffer == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001266 xmlGenericError(xmlGenericErrorContext,
1267 "xmlParserInputBufferGrow : out of memory !\n");
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001268 return(-1);
1269 }
Daniel Veillard5d211f42000-04-07 17:00:24 +00001270
1271 /*
1272 * Call the read method for this I/O type.
1273 */
1274 if (in->readcallback != NULL) {
1275 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001276 } else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001277 xmlGenericError(xmlGenericErrorContext,
1278 "xmlParserInputBufferGrow : no input !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001279 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001280 return(-1);
1281 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001282 if (res < 0) {
1283 perror ("read error");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001284 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001285 return(-1);
1286 }
Daniel Veillardbe803962000-06-28 23:40:59 +00001287 len = res;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001288 if (in->encoder != NULL) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001289 /*
1290 * Store the data in the incoming raw buffer
1291 */
1292 if (in->raw == NULL) {
1293 in->raw = xmlBufferCreate();
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001294 }
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001295 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
Daniel Veillardcf461992000-03-14 18:30:20 +00001296
1297 /*
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001298 * convert as much as possible to the parser reading buffer.
Daniel Veillardcf461992000-03-14 18:30:20 +00001299 */
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001300 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1301 if (nbchars < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001302 xmlGenericError(xmlGenericErrorContext,
1303 "xmlParserInputBufferGrow: encoder error\n");
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001304 return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00001305 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001306 } else {
Daniel Veillardbe803962000-06-28 23:40:59 +00001307 nbchars = len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001308 buffer[nbchars] = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001309 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001310 }
1311#ifdef DEBUG_INPUT
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001312 xmlGenericError(xmlGenericErrorContext,
1313 "I/O: read %d chars, buffer %d/%d\n",
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001314 nbchars, in->buffer->use, in->buffer->size);
1315#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001316 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001317 return(nbchars);
1318}
1319
1320/**
1321 * xmlParserInputBufferRead:
1322 * @in: a buffered parser input
1323 * @len: indicative value of the amount of chars to read
1324 *
1325 * Refresh the content of the input buffer, the old data are considered
1326 * consumed
1327 * This routine handle the I18N transcoding to internal UTF-8
1328 *
1329 * Returns the number of chars read and stored in the buffer, or -1
1330 * in case of error.
1331 */
1332int
1333xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1334 /* xmlBufferEmpty(in->buffer); */
Daniel Veillard5d211f42000-04-07 17:00:24 +00001335 if (in->readcallback != NULL)
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001336 return(xmlParserInputBufferGrow(in, len));
1337 else
Daniel Veillardbe803962000-06-28 23:40:59 +00001338 return(-1);
1339}
1340
1341/**
1342 * xmlOutputBufferWrite:
1343 * @out: a buffered parser output
1344 * @len: the size in bytes of the array.
1345 * @buf: an char array
1346 *
1347 * Write the content of the array in the output I/O buffer
1348 * This routine handle the I18N transcoding from internal UTF-8
1349 * The buffer is lossless, i.e. will store in case of partial
1350 * or delayed writes.
1351 *
1352 * Returns the number of chars immediately written, or -1
1353 * in case of error.
1354 */
1355int
1356xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
1357 int nbchars = 0, ret;
1358
1359 if (len < 0) return(0);
1360
1361 /*
1362 * first handle encoding stuff.
1363 */
1364 if (out->encoder != NULL) {
1365 /*
1366 * Store the data in the incoming raw buffer
1367 */
1368 if (out->conv == NULL) {
1369 out->conv = xmlBufferCreate();
1370 }
1371 xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1372
1373 if (out->buffer->use < MINLEN)
1374 return(0);
1375
1376 /*
1377 * convert as much as possible to the parser reading buffer.
1378 */
1379 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1380 if (nbchars < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001381 xmlGenericError(xmlGenericErrorContext,
1382 "xmlOutputBufferWrite: encoder error\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00001383 return(-1);
1384 }
1385 nbchars = out->conv->use;
1386 } else {
1387 xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1388 nbchars = out->buffer->use;
1389 }
1390 if (nbchars < MINLEN)
1391 return(0);
1392
1393 /*
1394 * second write the stuff to the I/O channel
1395 */
1396 if (out->encoder != NULL) {
1397 ret = out->writecallback(out->context,
1398 (const char *)out->conv->content, nbchars);
1399 if (ret >= 0)
1400 xmlBufferShrink(out->conv, nbchars);
1401 } else {
1402 ret = out->writecallback(out->context,
1403 (const char *)out->buffer->content, nbchars);
1404 if (ret >= 0)
1405 xmlBufferShrink(out->buffer, nbchars);
1406 }
1407 if (ret < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001408 xmlGenericError(xmlGenericErrorContext,
1409 "I/O: error %d writing %d bytes\n", ret, nbchars);
Daniel Veillardbe803962000-06-28 23:40:59 +00001410 return(ret);
1411 }
1412 out->written += ret;
1413
1414#ifdef DEBUG_INPUT
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001415 xmlGenericError(xmlGenericErrorContext,
1416 "I/O: wrote %d chars\n", ret);
Daniel Veillardbe803962000-06-28 23:40:59 +00001417#endif
1418 return(nbchars);
1419}
1420
1421/**
1422 * xmlOutputBufferWriteString:
1423 * @out: a buffered parser output
1424 * @str: a zero terminated C string
1425 *
1426 * Write the content of the string in the output I/O buffer
1427 * This routine handle the I18N transcoding from internal UTF-8
1428 * The buffer is lossless, i.e. will store in case of partial
1429 * or delayed writes.
1430 *
1431 * Returns the number of chars immediately written, or -1
1432 * in case of error.
1433 */
1434int
1435xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
1436 int len;
1437
1438 if (str == NULL)
1439 return(-1);
1440 len = strlen(str);
1441
1442 if (len > 0)
1443 return(xmlOutputBufferWrite(out, len, str));
1444 return(len);
1445}
1446
1447/**
1448 * xmlOutputBufferFlush:
1449 * @out: a buffered output
1450 *
1451 * flushes the output I/O channel
1452 *
1453 * Returns the number of byte written or -1 in case of error.
1454 */
1455int
1456xmlOutputBufferFlush(xmlOutputBufferPtr out) {
1457 int nbchars = 0, ret;
1458
1459 /*
1460 * first handle encoding stuff.
1461 */
1462 if ((out->conv != NULL) && (out->encoder != NULL)) {
1463 /*
1464 * convert as much as possible to the parser reading buffer.
1465 */
1466 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1467 if (nbchars < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001468 xmlGenericError(xmlGenericErrorContext,
1469 "xmlOutputBufferWrite: encoder error\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00001470 return(-1);
1471 }
1472 }
1473
1474 /*
1475 * second flush the stuff to the I/O channel
1476 */
1477 if ((out->conv != NULL) && (out->encoder != NULL)) {
1478 ret = out->writecallback(out->context,
1479 (const char *)out->conv->content, out->conv->use);
1480 if (ret >= 0)
1481 xmlBufferShrink(out->conv, ret);
1482 } else {
1483 ret = out->writecallback(out->context,
1484 (const char *)out->buffer->content, out->buffer->use);
1485 if (ret >= 0)
1486 xmlBufferShrink(out->buffer, ret);
1487 }
1488 if (ret < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001489 xmlGenericError(xmlGenericErrorContext,
1490 "I/O: error %d flushing %d bytes\n", ret, nbchars);
Daniel Veillardbe803962000-06-28 23:40:59 +00001491 return(ret);
1492 }
1493 out->written += ret;
1494
1495#ifdef DEBUG_INPUT
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001496 xmlGenericError(xmlGenericErrorContext,
1497 "I/O: flushed %d chars\n", ret);
Daniel Veillardbe803962000-06-28 23:40:59 +00001498#endif
1499 return(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001500}
1501
Daniel Veillardb05deb71999-08-10 19:04:08 +00001502/*
1503 * xmlParserGetDirectory:
1504 * @filename: the path to a file
1505 *
1506 * lookup the directory for that file
1507 *
1508 * Returns a new allocated string containing the directory, or NULL.
1509 */
1510char *
1511xmlParserGetDirectory(const char *filename) {
1512 char *ret = NULL;
1513 char dir[1024];
1514 char *cur;
1515 char sep = '/';
1516
Daniel Veillard5d211f42000-04-07 17:00:24 +00001517 if (xmlInputCallbackInitialized == 0)
1518 xmlRegisterDefaultInputCallbacks();
1519
Daniel Veillardb05deb71999-08-10 19:04:08 +00001520 if (filename == NULL) return(NULL);
1521#ifdef WIN32
1522 sep = '\\';
1523#endif
1524
1525 strncpy(dir, filename, 1023);
1526 dir[1023] = 0;
1527 cur = &dir[strlen(dir)];
1528 while (cur > dir) {
1529 if (*cur == sep) break;
1530 cur --;
1531 }
1532 if (*cur == sep) {
1533 if (cur == dir) dir[1] = 0;
1534 else *cur = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001535 ret = xmlMemStrdup(dir);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001536 } else {
1537 if (getcwd(dir, 1024) != NULL) {
1538 dir[1023] = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001539 ret = xmlMemStrdup(dir);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001540 }
1541 }
1542 return(ret);
1543}
1544
Daniel Veillardb96e6431999-08-29 21:02:19 +00001545/****************************************************************
1546 * *
1547 * External entities loading *
1548 * *
1549 ****************************************************************/
1550
1551/*
1552 * xmlDefaultExternalEntityLoader:
1553 * @URL: the URL for the entity to load
1554 * @ID: the System ID for the entity to load
Daniel Veillard686d6b62000-01-03 11:08:02 +00001555 * @ctxt: the context in which the entity is called or NULL
Daniel Veillardb96e6431999-08-29 21:02:19 +00001556 *
1557 * By default we don't load external entitites, yet.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001558 *
1559 * Returns a new allocated xmlParserInputPtr, or NULL.
1560 */
1561static
1562xmlParserInputPtr
1563xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillard686d6b62000-01-03 11:08:02 +00001564 xmlParserCtxtPtr ctxt) {
1565 xmlParserInputPtr ret = NULL;
Daniel Veillard39c7d712000-09-10 16:14:55 +00001566
Daniel Veillardb96e6431999-08-29 21:02:19 +00001567#ifdef DEBUG_EXTERNAL_ENTITIES
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001568 xmlGenericError(xmlGenericErrorContext,
1569 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001570#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001571 if (URL == NULL) {
1572 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001573 ctxt->sax->warning(ctxt,
1574 "failed to load external entity \"%s\"\n", ID);
Daniel Veillard686d6b62000-01-03 11:08:02 +00001575 return(NULL);
1576 }
1577 ret = xmlNewInputFromFile(ctxt, URL);
1578 if (ret == NULL) {
1579 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001580 ctxt->sax->warning(ctxt,
1581 "failed to load external entity \"%s\"\n", URL);
Daniel Veillard686d6b62000-01-03 11:08:02 +00001582 }
1583 return(ret);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001584}
1585
1586static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1587 xmlDefaultExternalEntityLoader;
1588
1589/*
1590 * xmlSetExternalEntityLoader:
1591 * @f: the new entity resolver function
1592 *
1593 * Changes the defaultexternal entity resolver function for the application
1594 */
1595void
1596xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1597 xmlCurrentExternalEntityLoader = f;
1598}
1599
1600/*
1601 * xmlGetExternalEntityLoader:
1602 *
1603 * Get the default external entity resolver function for the application
1604 *
1605 * Returns the xmlExternalEntityLoader function pointer
1606 */
1607xmlExternalEntityLoader
1608xmlGetExternalEntityLoader(void) {
1609 return(xmlCurrentExternalEntityLoader);
1610}
1611
1612/*
1613 * xmlLoadExternalEntity:
1614 * @URL: the URL for the entity to load
1615 * @ID: the System ID for the entity to load
Daniel Veillard686d6b62000-01-03 11:08:02 +00001616 * @ctxt: the context in which the entity is called or NULL
Daniel Veillardb96e6431999-08-29 21:02:19 +00001617 *
1618 * Load an external entity, note that the use of this function for
1619 * unparsed entities may generate problems
1620 * TODO: a more generic External entitiy API must be designed
1621 *
1622 * Returns the xmlParserInputPtr or NULL
1623 */
1624xmlParserInputPtr
1625xmlLoadExternalEntity(const char *URL, const char *ID,
Daniel Veillard686d6b62000-01-03 11:08:02 +00001626 xmlParserCtxtPtr ctxt) {
1627 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001628}
1629