blob: 38de65923a5d9877bfab63e157b8ed2d84786295 [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
Daniel Veillardce6e98d2000-11-25 09:54:49 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
Daniel Veillarde2d034d1999-07-27 19:52:06 +00009 */
10
Daniel Veillard7f7d1111999-09-22 09:46:25 +000011#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000012#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000013#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +000014#include "config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000015#endif
Daniel Veillarde2d034d1999-07-27 19:52:06 +000016
Daniel Veillard7f7d1111999-09-22 09:46:25 +000017#include <stdio.h>
18#include <string.h>
19
20#ifdef HAVE_SYS_TYPES_H
Daniel Veillarde2d034d1999-07-27 19:52:06 +000021#include <sys/types.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000022#endif
23#ifdef HAVE_SYS_STAT_H
Daniel Veillarde2d034d1999-07-27 19:52:06 +000024#include <sys/stat.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000025#endif
26#ifdef HAVE_FCNTL_H
Daniel Veillarde2d034d1999-07-27 19:52:06 +000027#include <fcntl.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000028#endif
Daniel Veillarde2d034d1999-07-27 19:52:06 +000029#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000032#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
Daniel Veillarde2d034d1999-07-27 19:52:06 +000035#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
38
Daniel Veillard361d8452000-04-03 19:48:13 +000039#include <libxml/xmlmemory.h>
40#include <libxml/parser.h>
41#include <libxml/parserInternals.h>
42#include <libxml/xmlIO.h>
43#include <libxml/nanohttp.h>
44#include <libxml/nanoftp.h>
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000045#include <libxml/xmlerror.h>
Daniel Veillarde2d034d1999-07-27 19:52:06 +000046
Daniel Veillardce6e98d2000-11-25 09:54:49 +000047#ifdef VMS
48#define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
49#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
50#endif
51
Daniel Veillarde2d034d1999-07-27 19:52:06 +000052/* #define VERBOSE_FAILURE */
Daniel Veillardb96e6431999-08-29 21:02:19 +000053/* #define DEBUG_EXTERNAL_ENTITIES */
Daniel Veillardbe803962000-06-28 23:40:59 +000054/* #define DEBUG_INPUT */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000055
56#ifdef DEBUG_INPUT
57#define MINLEN 40
58#else
59#define MINLEN 4000
60#endif
61
Daniel Veillard5d211f42000-04-07 17:00:24 +000062/*
63 * Input I/O callback sets
64 */
65typedef struct _xmlInputCallback {
66 xmlInputMatchCallback matchcallback;
67 xmlInputOpenCallback opencallback;
68 xmlInputReadCallback readcallback;
69 xmlInputCloseCallback closecallback;
70} xmlInputCallback;
71
72#define MAX_INPUT_CALLBACK 15
73
74xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
75int xmlInputCallbackNr = 0;
76int xmlInputCallbackInitialized = 0;
77
Daniel Veillardbe803962000-06-28 23:40:59 +000078/*
79 * Output I/O callback sets
80 */
81typedef struct _xmlOutputCallback {
82 xmlOutputMatchCallback matchcallback;
83 xmlOutputOpenCallback opencallback;
84 xmlOutputWriteCallback writecallback;
85 xmlOutputCloseCallback closecallback;
86} xmlOutputCallback;
87
88#define MAX_OUTPUT_CALLBACK 15
89
90xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
91int xmlOutputCallbackNr = 0;
92int xmlOutputCallbackInitialized = 0;
93
Daniel Veillard5d211f42000-04-07 17:00:24 +000094/************************************************************************
95 * *
96 * Standard I/O for file accesses *
97 * *
98 ************************************************************************/
99
Daniel Veillard46e370e2000-07-21 20:32:03 +0000100int
101xmlNop(void) {
102 return(0);
103}
104
Daniel Veillard5d211f42000-04-07 17:00:24 +0000105/**
106 * xmlFdMatch:
107 * @filename: the URI for matching
108 *
109 * input from file descriptor
110 *
111 * Returns 1 if matches, 0 otherwise
112 */
113int
114xmlFdMatch (const char *filename) {
115 return(1);
116}
117
118/**
119 * xmlFdOpen:
120 * @filename: the URI for matching
121 *
122 * input from file descriptor, supports compressed input
123 * if @filename is " " then the standard input is used
124 *
125 * Returns an I/O context or NULL in case of error
126 */
127void *
128xmlFdOpen (const char *filename) {
129 const char *path = NULL;
130 int fd;
131
132 if (!strcmp(filename, "-")) {
133 fd = 0;
134 return((void *) fd);
135 }
136
137 if (!strncmp(filename, "file://localhost", 16))
138 path = &filename[16];
139 else if (!strncmp(filename, "file:///", 8))
140 path = &filename[8];
141 else if (filename[0] == '/')
142 path = filename;
143 if (path == NULL)
144 return(NULL);
145
146#ifdef WIN32
147 fd = _open (filename, O_RDONLY | _O_BINARY);
148#else
149 fd = open (filename, O_RDONLY);
150#endif
151
152 return((void *) fd);
153}
154
155/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000156 * xmlFdOpenW:
157 * @filename: the URI for matching
158 *
159 * input from file descriptor,
160 * if @filename is "-" then the standard output is used
161 *
162 * Returns an I/O context or NULL in case of error
163 */
164void *
165xmlFdOpenW (const char *filename) {
166 const char *path = NULL;
167 int fd;
168
169 if (!strcmp(filename, "-")) {
170 fd = 1;
171 return((void *) fd);
172 }
173
174 if (!strncmp(filename, "file://localhost", 16))
175 path = &filename[16];
176 else if (!strncmp(filename, "file:///", 8))
177 path = &filename[8];
178 else if (filename[0] == '/')
179 path = filename;
180 if (path == NULL)
181 return(NULL);
182
183 fd = open (filename, O_WRONLY);
184
185 return((void *) fd);
186}
187
188/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000189 * xmlFdRead:
190 * @context: the I/O context
191 * @buffer: where to drop data
Daniel Veillardbe803962000-06-28 23:40:59 +0000192 * @len: number of bytes to read
Daniel Veillard5d211f42000-04-07 17:00:24 +0000193 *
194 * Read @len bytes to @buffer from the I/O channel.
195 *
196 * Returns the number of bytes written
197 */
198int
199xmlFdRead (void * context, char * buffer, int len) {
200 return(read((int) context, &buffer[0], len));
201}
202
203/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000204 * xmlFdWrite:
205 * @context: the I/O context
206 * @buffer: where to get data
207 * @len: number of bytes to write
208 *
209 * Write @len bytes from @buffer to the I/O channel.
210 *
211 * Returns the number of bytes written
212 */
213int
214xmlFdWrite (void * context, const char * buffer, int len) {
215 return(write((int) context, &buffer[0], len));
216}
217
218/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000219 * xmlFdClose:
220 * @context: the I/O context
221 *
222 * Close an I/O channel
223 */
224void
225xmlFdClose (void * context) {
226 close((int) context);
227}
228
229/**
230 * xmlFileMatch:
231 * @filename: the URI for matching
232 *
233 * input from FILE *
234 *
235 * Returns 1 if matches, 0 otherwise
236 */
237int
238xmlFileMatch (const char *filename) {
239 return(1);
240}
241
242/**
243 * xmlFileOpen:
244 * @filename: the URI for matching
245 *
246 * input from FILE *, supports compressed input
247 * if @filename is " " then the standard input is used
248 *
249 * Returns an I/O context or NULL in case of error
250 */
251void *
252xmlFileOpen (const char *filename) {
253 const char *path = NULL;
254 FILE *fd;
255
256 if (!strcmp(filename, "-")) {
257 fd = stdin;
258 return((void *) fd);
259 }
260
261 if (!strncmp(filename, "file://localhost", 16))
262 path = &filename[16];
263 else if (!strncmp(filename, "file:///", 8))
264 path = &filename[8];
265 else
266 path = filename;
267 if (path == NULL)
268 return(NULL);
269
270#ifdef WIN32
271 fd = fopen(path, "rb");
272#else
273 fd = fopen(path, "r");
274#endif /* WIN32 */
275 return((void *) fd);
276}
277
278/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000279 * xmlFileOpenW:
280 * @filename: the URI for matching
281 *
282 * output to from FILE *,
283 * if @filename is "-" then the standard output is used
284 *
285 * Returns an I/O context or NULL in case of error
286 */
287void *
288xmlFileOpenW (const char *filename) {
289 const char *path = NULL;
290 FILE *fd;
291
292 if (!strcmp(filename, "-")) {
293 fd = stdout;
294 return((void *) fd);
295 }
296
297 if (!strncmp(filename, "file://localhost", 16))
298 path = &filename[16];
299 else if (!strncmp(filename, "file:///", 8))
300 path = &filename[8];
301 else
302 path = filename;
303 if (path == NULL)
304 return(NULL);
305
306 fd = fopen(path, "w");
307 return((void *) fd);
308}
309
310/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000311 * xmlFileRead:
312 * @context: the I/O context
313 * @buffer: where to drop data
314 * @len: number of bytes to write
315 *
316 * Read @len bytes to @buffer from the I/O channel.
317 *
318 * Returns the number of bytes written
319 */
320int
321xmlFileRead (void * context, char * buffer, int len) {
322 return(fread(&buffer[0], 1, len, (FILE *) context));
323}
324
325/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000326 * xmlFileWrite:
327 * @context: the I/O context
328 * @buffer: where to drop data
329 * @len: number of bytes to write
330 *
331 * Write @len bytes from @buffer to the I/O channel.
332 *
333 * Returns the number of bytes written
334 */
335int
336xmlFileWrite (void * context, const char * buffer, int len) {
337 return(fwrite(&buffer[0], 1, len, (FILE *) context));
338}
339
340/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000341 * xmlFileClose:
342 * @context: the I/O context
343 *
344 * Close an I/O channel
345 */
346void
347xmlFileClose (void * context) {
348 fclose((FILE *) context);
349}
350
Daniel Veillard52afe802000-10-22 16:56:02 +0000351/**
352 * xmlFileFlush:
353 * @context: the I/O context
354 *
355 * Flush an I/O channel
356 */
357void
358xmlFileFlush (void * context) {
359 fflush((FILE *) context);
360}
361
Daniel Veillard5d211f42000-04-07 17:00:24 +0000362#ifdef HAVE_ZLIB_H
363/************************************************************************
364 * *
365 * I/O for compressed file accesses *
366 * *
367 ************************************************************************/
368/**
369 * xmlGzfileMatch:
370 * @filename: the URI for matching
371 *
372 * input from compressed file test
373 *
374 * Returns 1 if matches, 0 otherwise
375 */
376int
377xmlGzfileMatch (const char *filename) {
378 return(1);
379}
380
381/**
382 * xmlGzfileOpen:
383 * @filename: the URI for matching
384 *
385 * input from compressed file open
386 * if @filename is " " then the standard input is used
387 *
388 * Returns an I/O context or NULL in case of error
389 */
390void *
391xmlGzfileOpen (const char *filename) {
392 const char *path = NULL;
393 gzFile fd;
394
395 if (!strcmp(filename, "-")) {
Daniel Veillard2f971a22000-10-12 23:26:32 +0000396 fd = gzdopen(fileno(stdin), "rb");
Daniel Veillard5d211f42000-04-07 17:00:24 +0000397 return((void *) fd);
398 }
399
400 if (!strncmp(filename, "file://localhost", 16))
401 path = &filename[16];
402 else if (!strncmp(filename, "file:///", 8))
Daniel Veillardd8aa7cb2001-01-18 15:21:36 +0000403 path = &filename[7];
Daniel Veillard5d211f42000-04-07 17:00:24 +0000404 else
405 path = filename;
406
Daniel Veillardd8aa7cb2001-01-18 15:21:36 +0000407 fd = gzopen(path, "rb");
Daniel Veillard5d211f42000-04-07 17:00:24 +0000408 return((void *) fd);
409}
410
411/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000412 * xmlGzfileOpenW:
413 * @filename: the URI for matching
414 * @compression: the compression factor (0 - 9 included)
415 *
416 * input from compressed file open
417 * if @filename is " " then the standard input is used
418 *
419 * Returns an I/O context or NULL in case of error
420 */
421void *
422xmlGzfileOpenW (const char *filename, int compression) {
423 const char *path = NULL;
424 char mode[15];
425 gzFile fd;
426
Daniel Veillard2f971a22000-10-12 23:26:32 +0000427 sprintf(mode, "wb%d", compression);
Daniel Veillardbe803962000-06-28 23:40:59 +0000428 if (!strcmp(filename, "-")) {
429 fd = gzdopen(1, mode);
430 return((void *) fd);
431 }
432
433 if (!strncmp(filename, "file://localhost", 16))
434 path = &filename[16];
435 else if (!strncmp(filename, "file:///", 8))
436 path = &filename[8];
437 else
438 path = filename;
439
440 fd = gzopen(filename, mode);
441 return((void *) fd);
442}
443
444/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000445 * xmlGzfileRead:
446 * @context: the I/O context
447 * @buffer: where to drop data
448 * @len: number of bytes to write
449 *
450 * Read @len bytes to @buffer from the compressed I/O channel.
451 *
452 * Returns the number of bytes written
453 */
454int
455xmlGzfileRead (void * context, char * buffer, int len) {
456 return(gzread((gzFile) context, &buffer[0], len));
457}
458
459/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000460 * xmlGzfileWrite:
461 * @context: the I/O context
462 * @buffer: where to drop data
463 * @len: number of bytes to write
464 *
465 * Write @len bytes from @buffer to the compressed I/O channel.
466 *
467 * Returns the number of bytes written
468 */
469int
470xmlGzfileWrite (void * context, const char * buffer, int len) {
471 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
472}
473
474/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000475 * xmlGzfileClose:
476 * @context: the I/O context
477 *
478 * Close a compressed I/O channel
479 */
480void
481xmlGzfileClose (void * context) {
482 gzclose((gzFile) context);
483}
484#endif /* HAVE_ZLIB_H */
485
486#ifdef LIBXML_HTTP_ENABLED
487/************************************************************************
488 * *
489 * I/O for HTTP file accesses *
490 * *
491 ************************************************************************/
492/**
493 * xmlIOHTTPMatch:
494 * @filename: the URI for matching
495 *
496 * check if the URI matches an HTTP one
497 *
498 * Returns 1 if matches, 0 otherwise
499 */
500int
501xmlIOHTTPMatch (const char *filename) {
502 if (!strncmp(filename, "http://", 7))
503 return(1);
504 return(0);
505}
506
507/**
508 * xmlIOHTTPOpen:
509 * @filename: the URI for matching
510 *
511 * open an HTTP I/O channel
512 *
513 * Returns an I/O context or NULL in case of error
514 */
515void *
516xmlIOHTTPOpen (const char *filename) {
517 return(xmlNanoHTTPOpen(filename, NULL));
518}
519
520/**
521 * xmlIOHTTPRead:
522 * @context: the I/O context
523 * @buffer: where to drop data
524 * @len: number of bytes to write
525 *
526 * Read @len bytes to @buffer from the I/O channel.
527 *
528 * Returns the number of bytes written
529 */
530int
531xmlIOHTTPRead(void * context, char * buffer, int len) {
532 return(xmlNanoHTTPRead(context, &buffer[0], len));
533}
534
535/**
536 * xmlIOHTTPClose:
537 * @context: the I/O context
538 *
539 * Close an HTTP I/O channel
540 */
541void
542xmlIOHTTPClose (void * context) {
543 xmlNanoHTTPClose(context);
544}
545#endif /* LIBXML_HTTP_ENABLED */
546
547#ifdef LIBXML_FTP_ENABLED
548/************************************************************************
549 * *
550 * I/O for FTP file accesses *
551 * *
552 ************************************************************************/
553/**
554 * xmlIOFTPMatch:
555 * @filename: the URI for matching
556 *
557 * check if the URI matches an FTP one
558 *
559 * Returns 1 if matches, 0 otherwise
560 */
561int
562xmlIOFTPMatch (const char *filename) {
563 if (!strncmp(filename, "ftp://", 6))
564 return(1);
565 return(0);
566}
567
568/**
569 * xmlIOFTPOpen:
570 * @filename: the URI for matching
571 *
572 * open an FTP I/O channel
573 *
574 * Returns an I/O context or NULL in case of error
575 */
576void *
577xmlIOFTPOpen (const char *filename) {
578 return(xmlNanoFTPOpen(filename));
579}
580
581/**
582 * xmlIOFTPRead:
583 * @context: the I/O context
584 * @buffer: where to drop data
585 * @len: number of bytes to write
586 *
587 * Read @len bytes to @buffer from the I/O channel.
588 *
589 * Returns the number of bytes written
590 */
591int
592xmlIOFTPRead(void * context, char * buffer, int len) {
593 return(xmlNanoFTPRead(context, &buffer[0], len));
594}
595
596/**
597 * xmlIOFTPClose:
598 * @context: the I/O context
599 *
600 * Close an FTP I/O channel
601 */
602void
603xmlIOFTPClose (void * context) {
604 xmlNanoFTPClose(context);
605}
606#endif /* LIBXML_FTP_ENABLED */
607
608
609/**
610 * xmlRegisterInputCallbacks:
611 * @match: the xmlInputMatchCallback
612 * @open: the xmlInputOpenCallback
613 * @read: the xmlInputReadCallback
614 * @close: the xmlInputCloseCallback
615 *
616 * Register a new set of I/O callback for handling parser input.
617 *
618 * Returns the registered handler number or -1 in case of error
619 */
620int
621xmlRegisterInputCallbacks(xmlInputMatchCallback match,
622 xmlInputOpenCallback open, xmlInputReadCallback read,
623 xmlInputCloseCallback close) {
624 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
625 return(-1);
626 }
627 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match;
628 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open;
629 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read;
630 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close;
631 return(xmlInputCallbackNr++);
632}
633
634/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000635 * xmlRegisterOutputCallbacks:
636 * @match: the xmlOutputMatchCallback
637 * @open: the xmlOutputOpenCallback
638 * @write: the xmlOutputWriteCallback
639 * @close: the xmlOutputCloseCallback
640 *
641 * Register a new set of I/O callback for handling output.
642 *
643 * Returns the registered handler number or -1 in case of error
644 */
645int
646xmlRegisterOutputCallbacks(xmlOutputMatchCallback match,
647 xmlOutputOpenCallback open, xmlOutputWriteCallback write,
648 xmlOutputCloseCallback close) {
649 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
650 return(-1);
651 }
652 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = match;
653 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = open;
654 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = write;
655 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = close;
656 return(xmlOutputCallbackNr++);
657}
658
659/**
Daniel Veillard5d211f42000-04-07 17:00:24 +0000660 * xmlRegisterDefaultInputCallbacks:
661 *
662 * Registers the default compiled-in I/O handlers.
663 */
664void
Daniel Veillardce6e98d2000-11-25 09:54:49 +0000665#ifdef VMS
666xmlRegisterDefInputCallbacks
667#else
668xmlRegisterDefaultInputCallbacks
669#endif
670(void) {
Daniel Veillard7cfce322000-10-04 12:40:27 +0000671 if (xmlInputCallbackInitialized)
672 return;
673
Daniel Veillard5d211f42000-04-07 17:00:24 +0000674 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
675 xmlFileRead, xmlFileClose);
676#ifdef HAVE_ZLIB_H
677 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
678 xmlGzfileRead, xmlGzfileClose);
679#endif /* HAVE_ZLIB_H */
680
681#ifdef LIBXML_HTTP_ENABLED
682 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
683 xmlIOHTTPRead, xmlIOHTTPClose);
684#endif /* LIBXML_HTTP_ENABLED */
685
686#ifdef LIBXML_FTP_ENABLED
687 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
688 xmlIOFTPRead, xmlIOFTPClose);
689#endif /* LIBXML_FTP_ENABLED */
Daniel Veillard7cfce322000-10-04 12:40:27 +0000690 xmlInputCallbackInitialized = 1;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000691}
692
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000693/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000694 * xmlRegisterDefaultOutputCallbacks:
695 *
696 * Registers the default compiled-in I/O handlers.
697 */
698void
Daniel Veillardce6e98d2000-11-25 09:54:49 +0000699#ifdef VMS
700xmlRegisterDefOutputCallbacks
701#else
702xmlRegisterDefaultOutputCallbacks
703#endif
704(void) {
Daniel Veillard7cfce322000-10-04 12:40:27 +0000705 if (xmlOutputCallbackInitialized)
706 return;
707
Daniel Veillardbe803962000-06-28 23:40:59 +0000708 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
709 xmlFileWrite, xmlFileClose);
710/*********************************
711 No way a-priori to distinguish between gzipped files from
712 uncompressed ones except opening if existing then closing
713 and saving with same compression ratio ... a pain.
714
715#ifdef HAVE_ZLIB_H
716 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
717 xmlGzfileWrite, xmlGzfileClose);
718#endif
719 No HTTP PUT support yet, patches welcome
720
721#ifdef LIBXML_HTTP_ENABLED
722 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
723 xmlIOHTTPWrite, xmlIOHTTPClose);
724#endif
725
726 Nor FTP PUT ....
727#ifdef LIBXML_FTP_ENABLED
728 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
729 xmlIOFTPWrite, xmlIOFTPClose);
730#endif
731 **********************************/
Daniel Veillard7cfce322000-10-04 12:40:27 +0000732 xmlOutputCallbackInitialized = 1;
Daniel Veillardbe803962000-06-28 23:40:59 +0000733}
734
735/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000736 * xmlAllocParserInputBuffer:
737 * @enc: the charset encoding if known
738 *
739 * Create a buffered parser input for progressive parsing
740 *
741 * Returns the new parser input or NULL
742 */
743xmlParserInputBufferPtr
744xmlAllocParserInputBuffer(xmlCharEncoding enc) {
745 xmlParserInputBufferPtr ret;
746
Daniel Veillard6454aec1999-09-02 22:04:43 +0000747 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000748 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000749 xmlGenericError(xmlGenericErrorContext,
750 "xmlAllocParserInputBuffer : out of memory!\n");
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000751 return(NULL);
752 }
753 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
754 ret->buffer = xmlBufferCreate();
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000755 if (ret->buffer == NULL) {
756 xmlFree(ret);
757 return(NULL);
758 }
759 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000760 ret->encoder = xmlGetCharEncodingHandler(enc);
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000761 if (ret->encoder != NULL)
762 ret->raw = xmlBufferCreate();
763 else
764 ret->raw = NULL;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000765 ret->readcallback = NULL;
766 ret->closecallback = NULL;
767 ret->context = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000768
769 return(ret);
770}
771
772/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000773 * xmlAllocOutputBuffer:
774 * @encoder: the encoding converter or NULL
775 *
776 * Create a buffered parser output
777 *
778 * Returns the new parser output or NULL
779 */
780xmlOutputBufferPtr
781xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
782 xmlOutputBufferPtr ret;
783
784 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
785 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000786 xmlGenericError(xmlGenericErrorContext,
787 "xmlAllocOutputBuffer : out of memory!\n");
Daniel Veillardbe803962000-06-28 23:40:59 +0000788 return(NULL);
789 }
790 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
791 ret->buffer = xmlBufferCreate();
792 if (ret->buffer == NULL) {
793 xmlFree(ret);
794 return(NULL);
795 }
796 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
797 ret->encoder = encoder;
798 if (encoder != NULL) {
799 ret->conv = xmlBufferCreateSize(4000);
800 /*
801 * This call is designed to initiate the encoder state
802 */
803 xmlCharEncOutFunc(encoder, ret->conv, NULL);
804 } else
805 ret->conv = NULL;
806 ret->writecallback = NULL;
807 ret->closecallback = NULL;
808 ret->context = NULL;
809 ret->written = 0;
810
811 return(ret);
812}
813
814/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000815 * xmlFreeParserInputBuffer:
816 * @in: a buffered parser input
817 *
818 * Free up the memory used by a buffered parser input
819 */
820void
821xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000822 if (in->raw) {
823 xmlBufferFree(in->raw);
824 in->raw = NULL;
825 }
826 if (in->encoder != NULL) {
827 xmlCharEncCloseFunc(in->encoder);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000828 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000829 if (in->closecallback != NULL) {
830 in->closecallback(in->context);
831 }
Daniel Veillard496a1cf2000-05-03 14:20:55 +0000832 if (in->buffer != NULL) {
833 xmlBufferFree(in->buffer);
834 in->buffer = NULL;
835 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000836
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000837 memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000838 xmlFree(in);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000839}
840
841/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000842 * xmlOutputBufferClose:
843 * @out: a buffered output
844 *
845 * flushes and close the output I/O channel
846 * and free up all the associated resources
847 *
848 * Returns the number of byte written or -1 in case of error.
849 */
850int
851xmlOutputBufferClose(xmlOutputBufferPtr out) {
852 int written;
853
854 if (out == NULL)
855 return(-1);
Daniel Veillard58770e72000-11-25 00:48:47 +0000856 if (out->writecallback != NULL)
857 xmlOutputBufferFlush(out);
Daniel Veillardbe803962000-06-28 23:40:59 +0000858 if (out->closecallback != NULL) {
859 out->closecallback(out->context);
860 }
861 written = out->written;
862 if (out->conv) {
863 xmlBufferFree(out->conv);
864 out->conv = NULL;
865 }
866 if (out->encoder != NULL) {
867 xmlCharEncCloseFunc(out->encoder);
868 }
869 if (out->buffer != NULL) {
870 xmlBufferFree(out->buffer);
871 out->buffer = NULL;
872 }
873
874 memset(out, 0xbe, (size_t) sizeof(xmlOutputBuffer));
875 xmlFree(out);
876 return(written);
877}
878
879/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000880 * xmlParserInputBufferCreateFilename:
Daniel Veillard5d211f42000-04-07 17:00:24 +0000881 * @URI: a C string containing the URI or filename
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000882 * @enc: the charset encoding if known
883 *
884 * Create a buffered parser input for the progressive parsing of a file
885 * If filename is "-' then we use stdin as the input.
886 * Automatic support for ZLIB/Compress compressed document is provided
887 * by default if found at compile-time.
Daniel Veillardcf461992000-03-14 18:30:20 +0000888 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000889 *
890 * Returns the new parser input or NULL
891 */
892xmlParserInputBufferPtr
Daniel Veillardce6e98d2000-11-25 09:54:49 +0000893#ifdef VMS
894xmlParserInputBufferCreateFname
895#else
896xmlParserInputBufferCreateFilename
897#endif
898(const char *URI, xmlCharEncoding enc) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000899 xmlParserInputBufferPtr ret;
Daniel Veillard5d211f42000-04-07 17:00:24 +0000900 int i;
901 void *context = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000902
Daniel Veillard5d211f42000-04-07 17:00:24 +0000903 if (xmlInputCallbackInitialized == 0)
904 xmlRegisterDefaultInputCallbacks();
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000905
Daniel Veillard5d211f42000-04-07 17:00:24 +0000906 if (URI == NULL) return(NULL);
907
908 /*
909 * Try to find one of the input accept method accepting taht scheme
910 * Go in reverse to give precedence to user defined handlers.
911 */
912 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
913 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
914 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
915 context = xmlInputCallbackTable[i].opencallback(URI);
916 if (context != NULL)
917 break;
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000918 }
Daniel Veillard5d211f42000-04-07 17:00:24 +0000919 }
920 if (context == NULL) {
Daniel Veillard5d211f42000-04-07 17:00:24 +0000921 return(NULL);
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000922 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000923
Daniel Veillardcf461992000-03-14 18:30:20 +0000924 /*
925 * Allocate the Input buffer front-end.
926 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000927 ret = xmlAllocParserInputBuffer(enc);
928 if (ret != NULL) {
Daniel Veillard5d211f42000-04-07 17:00:24 +0000929 ret->context = context;
930 ret->readcallback = xmlInputCallbackTable[i].readcallback;
931 ret->closecallback = xmlInputCallbackTable[i].closecallback;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000932 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000933 return(ret);
934}
935
936/**
Daniel Veillardbe803962000-06-28 23:40:59 +0000937 * xmlOutputBufferCreateFilename:
938 * @URI: a C string containing the URI or filename
939 * @encoder: the encoding converter or NULL
940 * @compression: the compression ration (0 none, 9 max).
941 *
942 * Create a buffered output for the progressive saving of a file
943 * If filename is "-' then we use stdout as the output.
944 * Automatic support for ZLIB/Compress compressed document is provided
945 * by default if found at compile-time.
946 * TODO: currently if compression is set, the library only support
947 * writing to a local file.
948 *
949 * Returns the new output or NULL
950 */
951xmlOutputBufferPtr
952xmlOutputBufferCreateFilename(const char *URI,
953 xmlCharEncodingHandlerPtr encoder,
954 int compression) {
955 xmlOutputBufferPtr ret;
956 int i;
957 void *context = NULL;
958
959 if (xmlOutputCallbackInitialized == 0)
960 xmlRegisterDefaultOutputCallbacks();
961
962 if (URI == NULL) return(NULL);
963
964#ifdef HAVE_ZLIB_H
965 if ((compression > 0) && (compression <= 9)) {
966 context = xmlGzfileOpenW(URI, compression);
967 if (context != NULL) {
968 ret = xmlAllocOutputBuffer(encoder);
969 if (ret != NULL) {
970 ret->context = context;
971 ret->writecallback = xmlGzfileWrite;
972 ret->closecallback = xmlGzfileClose;
973 }
974 return(ret);
975 }
976 }
977#endif
978
979 /*
980 * Try to find one of the output accept method accepting taht scheme
981 * Go in reverse to give precedence to user defined handlers.
982 */
983 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
984 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
985 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
986 context = xmlOutputCallbackTable[i].opencallback(URI);
987 if (context != NULL)
988 break;
989 }
990 }
991 if (context == NULL) {
Daniel Veillardbe803962000-06-28 23:40:59 +0000992 return(NULL);
993 }
994
995 /*
996 * Allocate the Output buffer front-end.
997 */
998 ret = xmlAllocOutputBuffer(encoder);
999 if (ret != NULL) {
1000 ret->context = context;
1001 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1002 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1003 }
1004 return(ret);
1005}
1006
1007/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001008 * xmlParserInputBufferCreateFile:
1009 * @file: a FILE*
1010 * @enc: the charset encoding if known
1011 *
1012 * Create a buffered parser input for the progressive parsing of a FILE *
1013 * buffered C I/O
1014 *
1015 * Returns the new parser input or NULL
1016 */
1017xmlParserInputBufferPtr
1018xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1019 xmlParserInputBufferPtr ret;
1020
Daniel Veillard5d211f42000-04-07 17:00:24 +00001021 if (xmlInputCallbackInitialized == 0)
1022 xmlRegisterDefaultInputCallbacks();
1023
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001024 if (file == NULL) return(NULL);
1025
1026 ret = xmlAllocParserInputBuffer(enc);
Daniel Veillard5d211f42000-04-07 17:00:24 +00001027 if (ret != NULL) {
1028 ret->context = file;
1029 ret->readcallback = xmlFileRead;
Daniel Veillard52afe802000-10-22 16:56:02 +00001030 ret->closecallback = xmlFileFlush;
Daniel Veillard5d211f42000-04-07 17:00:24 +00001031 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001032
1033 return(ret);
1034}
1035
1036/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001037 * xmlOutputBufferCreateFile:
1038 * @file: a FILE*
1039 * @encoder: the encoding converter or NULL
1040 *
1041 * Create a buffered output for the progressive saving to a FILE *
1042 * buffered C I/O
1043 *
1044 * Returns the new parser output or NULL
1045 */
1046xmlOutputBufferPtr
1047xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1048 xmlOutputBufferPtr ret;
1049
1050 if (xmlOutputCallbackInitialized == 0)
1051 xmlRegisterDefaultOutputCallbacks();
1052
1053 if (file == NULL) return(NULL);
1054
1055 ret = xmlAllocOutputBuffer(encoder);
1056 if (ret != NULL) {
1057 ret->context = file;
1058 ret->writecallback = xmlFileWrite;
Daniel Veillard52afe802000-10-22 16:56:02 +00001059 ret->closecallback = xmlFileFlush;
Daniel Veillardbe803962000-06-28 23:40:59 +00001060 }
1061
1062 return(ret);
1063}
1064
1065/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001066 * xmlParserInputBufferCreateFd:
1067 * @fd: a file descriptor number
1068 * @enc: the charset encoding if known
1069 *
1070 * Create a buffered parser input for the progressive parsing for the input
1071 * from a file descriptor
1072 *
1073 * Returns the new parser input or NULL
1074 */
1075xmlParserInputBufferPtr
1076xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1077 xmlParserInputBufferPtr ret;
1078
1079 if (fd < 0) return(NULL);
1080
1081 ret = xmlAllocParserInputBuffer(enc);
Daniel Veillard5d211f42000-04-07 17:00:24 +00001082 if (ret != NULL) {
1083 ret->context = (void *) fd;
1084 ret->readcallback = xmlFdRead;
1085 ret->closecallback = xmlFdClose;
1086 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001087
1088 return(ret);
1089}
1090
1091/**
Daniel Veillard46e370e2000-07-21 20:32:03 +00001092 * xmlParserInputBufferCreateMem:
1093 * @mem: the memory input
1094 * @size: the length of the memory block
1095 * @enc: the charset encoding if known
1096 *
1097 * Create a buffered parser input for the progressive parsing for the input
Daniel Veillardf060a412001-01-03 20:52:44 +00001098 * from a memory area.
Daniel Veillard46e370e2000-07-21 20:32:03 +00001099 *
1100 * Returns the new parser input or NULL
1101 */
1102xmlParserInputBufferPtr
1103xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1104 xmlParserInputBufferPtr ret;
1105
1106 if (size <= 0) return(NULL);
1107 if (mem == NULL) return(NULL);
1108
1109 ret = xmlAllocParserInputBuffer(enc);
1110 if (ret != NULL) {
1111 ret->context = (void *) mem;
1112 ret->readcallback = (xmlInputReadCallback) xmlNop;
1113 ret->closecallback = NULL;
1114 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1115 }
1116
1117 return(ret);
1118}
1119
1120/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001121 * xmlOutputBufferCreateFd:
1122 * @fd: a file descriptor number
1123 * @encoder: the encoding converter or NULL
1124 *
1125 * Create a buffered output for the progressive saving
1126 * to a file descriptor
1127 *
1128 * Returns the new parser output or NULL
1129 */
1130xmlOutputBufferPtr
1131xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1132 xmlOutputBufferPtr ret;
1133
1134 if (fd < 0) return(NULL);
1135
1136 ret = xmlAllocOutputBuffer(encoder);
1137 if (ret != NULL) {
1138 ret->context = (void *) fd;
1139 ret->writecallback = xmlFdWrite;
1140 ret->closecallback = xmlFdClose;
1141 }
1142
1143 return(ret);
1144}
1145
1146/**
Daniel Veillard5e873c42000-04-12 13:27:38 +00001147 * xmlParserInputBufferCreateIO:
1148 * @ioread: an I/O read function
1149 * @ioclose: an I/O close function
1150 * @ioctx: an I/O handler
1151 * @enc: the charset encoding if known
1152 *
1153 * Create a buffered parser input for the progressive parsing for the input
Daniel Veillardbe803962000-06-28 23:40:59 +00001154 * from an I/O handler
Daniel Veillard5e873c42000-04-12 13:27:38 +00001155 *
1156 * Returns the new parser input or NULL
1157 */
1158xmlParserInputBufferPtr
1159xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1160 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1161 xmlParserInputBufferPtr ret;
1162
1163 if (ioread == NULL) return(NULL);
1164
1165 ret = xmlAllocParserInputBuffer(enc);
1166 if (ret != NULL) {
1167 ret->context = (void *) ioctx;
1168 ret->readcallback = ioread;
1169 ret->closecallback = ioclose;
1170 }
1171
1172 return(ret);
1173}
1174
1175/**
Daniel Veillardbe803962000-06-28 23:40:59 +00001176 * xmlOutputBufferCreateIO:
1177 * @iowrite: an I/O write function
1178 * @ioclose: an I/O close function
1179 * @ioctx: an I/O handler
1180 * @enc: the charset encoding if known
1181 *
1182 * Create a buffered output for the progressive saving
1183 * to an I/O handler
1184 *
1185 * Returns the new parser output or NULL
1186 */
1187xmlOutputBufferPtr
1188xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1189 xmlOutputCloseCallback ioclose, void *ioctx,
1190 xmlCharEncodingHandlerPtr encoder) {
1191 xmlOutputBufferPtr ret;
1192
1193 if (iowrite == NULL) return(NULL);
1194
1195 ret = xmlAllocOutputBuffer(encoder);
1196 if (ret != NULL) {
1197 ret->context = (void *) ioctx;
1198 ret->writecallback = iowrite;
1199 ret->closecallback = ioclose;
1200 }
1201
1202 return(ret);
1203}
1204
1205/**
Daniel Veillard7f858501999-11-17 17:32:38 +00001206 * xmlParserInputBufferPush:
1207 * @in: a buffered parser input
Daniel Veillard7f858501999-11-17 17:32:38 +00001208 * @len: the size in bytes of the array.
Daniel Veillardbe803962000-06-28 23:40:59 +00001209 * @buf: an char array
Daniel Veillard7f858501999-11-17 17:32:38 +00001210 *
1211 * Push the content of the arry in the input buffer
1212 * This routine handle the I18N transcoding to internal UTF-8
1213 * This is used when operating the parser in progressive (push) mode.
1214 *
1215 * Returns the number of chars read and stored in the buffer, or -1
1216 * in case of error.
1217 */
1218int
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001219xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1220 int len, const char *buf) {
Daniel Veillard7f858501999-11-17 17:32:38 +00001221 int nbchars = 0;
1222
1223 if (len < 0) return(0);
1224 if (in->encoder != NULL) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001225 /*
1226 * Store the data in the incoming raw buffer
Daniel Veillard7f858501999-11-17 17:32:38 +00001227 */
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001228 if (in->raw == NULL) {
1229 in->raw = xmlBufferCreate();
1230 }
1231 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1232
1233 /*
1234 * convert as much as possible to the parser reading buffer.
1235 */
1236 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
Daniel Veillardcf461992000-03-14 18:30:20 +00001237 if (nbchars < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001238 xmlGenericError(xmlGenericErrorContext,
1239 "xmlParserInputBufferPush: encoder error\n");
Daniel Veillardcf461992000-03-14 18:30:20 +00001240 return(-1);
1241 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001242 } else {
1243 nbchars = len;
1244 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
Daniel Veillard7f858501999-11-17 17:32:38 +00001245 }
1246#ifdef DEBUG_INPUT
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001247 xmlGenericError(xmlGenericErrorContext,
1248 "I/O: pushed %d chars, buffer %d/%d\n",
Daniel Veillard7f858501999-11-17 17:32:38 +00001249 nbchars, in->buffer->use, in->buffer->size);
1250#endif
1251 return(nbchars);
1252}
1253
1254/**
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001255 * xmlParserInputBufferGrow:
1256 * @in: a buffered parser input
1257 * @len: indicative value of the amount of chars to read
1258 *
1259 * Grow up the content of the input buffer, the old data are preserved
1260 * This routine handle the I18N transcoding to internal UTF-8
Daniel Veillard7f858501999-11-17 17:32:38 +00001261 * This routine is used when operating the parser in normal (pull) mode
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001262 *
1263 * TODO: one should be able to remove one extra copy by copying directy
1264 * onto in->buffer or in->raw
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001265 *
1266 * Returns the number of chars read and stored in the buffer, or -1
1267 * in case of error.
1268 */
1269int
1270xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1271 char *buffer = NULL;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001272 int res = 0;
1273 int nbchars = 0;
1274 int buffree;
1275
1276 if ((len <= MINLEN) && (len != 4))
1277 len = MINLEN;
1278 buffree = in->buffer->size - in->buffer->use;
1279 if (buffree <= 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001280 xmlGenericError(xmlGenericErrorContext,
1281 "xmlParserInputBufferGrow : buffer full !\n");
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001282 return(0);
1283 }
1284 if (len > buffree)
1285 len = buffree;
1286
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001287 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001288 if (buffer == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001289 xmlGenericError(xmlGenericErrorContext,
1290 "xmlParserInputBufferGrow : out of memory !\n");
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001291 return(-1);
1292 }
Daniel Veillard5d211f42000-04-07 17:00:24 +00001293
1294 /*
1295 * Call the read method for this I/O type.
1296 */
1297 if (in->readcallback != NULL) {
1298 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001299 } else {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001300 xmlGenericError(xmlGenericErrorContext,
1301 "xmlParserInputBufferGrow : no input !\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001302 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001303 return(-1);
1304 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001305 if (res < 0) {
1306 perror ("read error");
Daniel Veillard6454aec1999-09-02 22:04:43 +00001307 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001308 return(-1);
1309 }
Daniel Veillardbe803962000-06-28 23:40:59 +00001310 len = res;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001311 if (in->encoder != NULL) {
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001312 /*
1313 * Store the data in the incoming raw buffer
1314 */
1315 if (in->raw == NULL) {
1316 in->raw = xmlBufferCreate();
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001317 }
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001318 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
Daniel Veillardcf461992000-03-14 18:30:20 +00001319
1320 /*
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001321 * convert as much as possible to the parser reading buffer.
Daniel Veillardcf461992000-03-14 18:30:20 +00001322 */
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001323 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1324 if (nbchars < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001325 xmlGenericError(xmlGenericErrorContext,
1326 "xmlParserInputBufferGrow: encoder error\n");
Daniel Veillard496a1cf2000-05-03 14:20:55 +00001327 return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00001328 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001329 } else {
Daniel Veillardbe803962000-06-28 23:40:59 +00001330 nbchars = len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001331 buffer[nbchars] = 0;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001332 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001333 }
1334#ifdef DEBUG_INPUT
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001335 xmlGenericError(xmlGenericErrorContext,
1336 "I/O: read %d chars, buffer %d/%d\n",
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001337 nbchars, in->buffer->use, in->buffer->size);
1338#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001339 xmlFree(buffer);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001340 return(nbchars);
1341}
1342
1343/**
1344 * xmlParserInputBufferRead:
1345 * @in: a buffered parser input
1346 * @len: indicative value of the amount of chars to read
1347 *
1348 * Refresh the content of the input buffer, the old data are considered
1349 * consumed
1350 * This routine handle the I18N transcoding to internal UTF-8
1351 *
1352 * Returns the number of chars read and stored in the buffer, or -1
1353 * in case of error.
1354 */
1355int
1356xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1357 /* xmlBufferEmpty(in->buffer); */
Daniel Veillard5d211f42000-04-07 17:00:24 +00001358 if (in->readcallback != NULL)
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001359 return(xmlParserInputBufferGrow(in, len));
1360 else
Daniel Veillardbe803962000-06-28 23:40:59 +00001361 return(-1);
1362}
1363
1364/**
1365 * xmlOutputBufferWrite:
1366 * @out: a buffered parser output
1367 * @len: the size in bytes of the array.
1368 * @buf: an char array
1369 *
1370 * Write the content of the array in the output I/O buffer
1371 * This routine handle the I18N transcoding from internal UTF-8
1372 * The buffer is lossless, i.e. will store in case of partial
1373 * or delayed writes.
1374 *
1375 * Returns the number of chars immediately written, or -1
1376 * in case of error.
1377 */
1378int
1379xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
Daniel Veillarde2488192001-01-04 10:54:22 +00001380 int nbchars = 0; /* number of chars to output to I/O */
1381 int ret; /* return from function call */
1382 int written = 0; /* number of char written to I/O so far */
1383 int chunk; /* number of byte curreent processed from buf */
Daniel Veillardbe803962000-06-28 23:40:59 +00001384
1385 if (len < 0) return(0);
1386
Daniel Veillarde2488192001-01-04 10:54:22 +00001387 do {
1388 chunk = len;
1389 if (chunk > 4 * MINLEN)
1390 chunk = 4 * MINLEN;
Daniel Veillardbe803962000-06-28 23:40:59 +00001391
1392 /*
Daniel Veillarde2488192001-01-04 10:54:22 +00001393 * first handle encoding stuff.
Daniel Veillardbe803962000-06-28 23:40:59 +00001394 */
Daniel Veillarde2488192001-01-04 10:54:22 +00001395 if (out->encoder != NULL) {
1396 /*
1397 * Store the data in the incoming raw buffer
1398 */
1399 if (out->conv == NULL) {
1400 out->conv = xmlBufferCreate();
1401 }
1402 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
1403
1404 if ((out->buffer->use < MINLEN) && (chunk == len))
1405 goto done;
1406
1407 /*
1408 * convert as much as possible to the parser reading buffer.
1409 */
1410 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1411 if (ret < 0) {
1412 xmlGenericError(xmlGenericErrorContext,
1413 "xmlOutputBufferWrite: encoder error\n");
1414 return(-1);
1415 }
1416 nbchars = out->conv->use;
1417 } else {
1418 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
1419 nbchars = out->buffer->use;
Daniel Veillardbe803962000-06-28 23:40:59 +00001420 }
Daniel Veillarde2488192001-01-04 10:54:22 +00001421 buf += chunk;
1422 len -= chunk;
Daniel Veillardbe803962000-06-28 23:40:59 +00001423
Daniel Veillarde2488192001-01-04 10:54:22 +00001424 if ((nbchars < MINLEN) && (len <= 0))
1425 goto done;
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001426
Daniel Veillarde2488192001-01-04 10:54:22 +00001427 if (out->writecallback) {
1428 /*
1429 * second write the stuff to the I/O channel
1430 */
1431 if (out->encoder != NULL) {
1432 ret = out->writecallback(out->context,
1433 (const char *)out->conv->content, nbchars);
1434 if (ret >= 0)
1435 xmlBufferShrink(out->conv, nbchars);
1436 } else {
1437 ret = out->writecallback(out->context,
1438 (const char *)out->buffer->content, nbchars);
1439 if (ret >= 0)
1440 xmlBufferShrink(out->buffer, nbchars);
1441 }
1442 if (ret < 0) {
1443 xmlGenericError(xmlGenericErrorContext,
1444 "I/O: error %d writing %d bytes\n", ret, nbchars);
1445 return(ret);
1446 }
1447 out->written += ret;
1448 }
1449 written += nbchars;
1450 } while (len > 0);
Daniel Veillardbe803962000-06-28 23:40:59 +00001451
Daniel Veillarde2488192001-01-04 10:54:22 +00001452done:
Daniel Veillardbe803962000-06-28 23:40:59 +00001453#ifdef DEBUG_INPUT
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001454 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde2488192001-01-04 10:54:22 +00001455 "I/O: wrote %d chars\n", written);
Daniel Veillardbe803962000-06-28 23:40:59 +00001456#endif
Daniel Veillarde2488192001-01-04 10:54:22 +00001457 return(written);
Daniel Veillardbe803962000-06-28 23:40:59 +00001458}
1459
1460/**
1461 * xmlOutputBufferWriteString:
1462 * @out: a buffered parser output
1463 * @str: a zero terminated C string
1464 *
1465 * Write the content of the string in the output I/O buffer
1466 * This routine handle the I18N transcoding from internal UTF-8
1467 * The buffer is lossless, i.e. will store in case of partial
1468 * or delayed writes.
1469 *
1470 * Returns the number of chars immediately written, or -1
1471 * in case of error.
1472 */
1473int
1474xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
1475 int len;
1476
1477 if (str == NULL)
1478 return(-1);
1479 len = strlen(str);
1480
1481 if (len > 0)
1482 return(xmlOutputBufferWrite(out, len, str));
1483 return(len);
1484}
1485
1486/**
1487 * xmlOutputBufferFlush:
1488 * @out: a buffered output
1489 *
1490 * flushes the output I/O channel
1491 *
1492 * Returns the number of byte written or -1 in case of error.
1493 */
1494int
1495xmlOutputBufferFlush(xmlOutputBufferPtr out) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001496 int nbchars = 0, ret = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00001497
1498 /*
1499 * first handle encoding stuff.
1500 */
1501 if ((out->conv != NULL) && (out->encoder != NULL)) {
1502 /*
1503 * convert as much as possible to the parser reading buffer.
1504 */
1505 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1506 if (nbchars < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001507 xmlGenericError(xmlGenericErrorContext,
1508 "xmlOutputBufferWrite: encoder error\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00001509 return(-1);
1510 }
1511 }
1512
1513 /*
1514 * second flush the stuff to the I/O channel
1515 */
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001516 if ((out->conv != NULL) && (out->encoder != NULL) &&
1517 (out->writecallback != NULL)) {
Daniel Veillardbe803962000-06-28 23:40:59 +00001518 ret = out->writecallback(out->context,
1519 (const char *)out->conv->content, out->conv->use);
1520 if (ret >= 0)
1521 xmlBufferShrink(out->conv, ret);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001522 } else if (out->writecallback != NULL) {
Daniel Veillardbe803962000-06-28 23:40:59 +00001523 ret = out->writecallback(out->context,
1524 (const char *)out->buffer->content, out->buffer->use);
1525 if (ret >= 0)
1526 xmlBufferShrink(out->buffer, ret);
1527 }
1528 if (ret < 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001529 xmlGenericError(xmlGenericErrorContext,
1530 "I/O: error %d flushing %d bytes\n", ret, nbchars);
Daniel Veillardbe803962000-06-28 23:40:59 +00001531 return(ret);
1532 }
1533 out->written += ret;
1534
1535#ifdef DEBUG_INPUT
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001536 xmlGenericError(xmlGenericErrorContext,
1537 "I/O: flushed %d chars\n", ret);
Daniel Veillardbe803962000-06-28 23:40:59 +00001538#endif
1539 return(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001540}
1541
Daniel Veillardb05deb71999-08-10 19:04:08 +00001542/*
1543 * xmlParserGetDirectory:
1544 * @filename: the path to a file
1545 *
1546 * lookup the directory for that file
1547 *
1548 * Returns a new allocated string containing the directory, or NULL.
1549 */
1550char *
1551xmlParserGetDirectory(const char *filename) {
1552 char *ret = NULL;
1553 char dir[1024];
1554 char *cur;
1555 char sep = '/';
1556
Daniel Veillard5d211f42000-04-07 17:00:24 +00001557 if (xmlInputCallbackInitialized == 0)
1558 xmlRegisterDefaultInputCallbacks();
1559
Daniel Veillardb05deb71999-08-10 19:04:08 +00001560 if (filename == NULL) return(NULL);
1561#ifdef WIN32
1562 sep = '\\';
1563#endif
1564
1565 strncpy(dir, filename, 1023);
1566 dir[1023] = 0;
1567 cur = &dir[strlen(dir)];
1568 while (cur > dir) {
1569 if (*cur == sep) break;
1570 cur --;
1571 }
1572 if (*cur == sep) {
1573 if (cur == dir) dir[1] = 0;
1574 else *cur = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001575 ret = xmlMemStrdup(dir);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001576 } else {
1577 if (getcwd(dir, 1024) != NULL) {
1578 dir[1023] = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +00001579 ret = xmlMemStrdup(dir);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001580 }
1581 }
1582 return(ret);
1583}
1584
Daniel Veillardb96e6431999-08-29 21:02:19 +00001585/****************************************************************
1586 * *
1587 * External entities loading *
1588 * *
1589 ****************************************************************/
1590
1591/*
1592 * xmlDefaultExternalEntityLoader:
1593 * @URL: the URL for the entity to load
1594 * @ID: the System ID for the entity to load
Daniel Veillard686d6b62000-01-03 11:08:02 +00001595 * @ctxt: the context in which the entity is called or NULL
Daniel Veillardb96e6431999-08-29 21:02:19 +00001596 *
1597 * By default we don't load external entitites, yet.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001598 *
1599 * Returns a new allocated xmlParserInputPtr, or NULL.
1600 */
1601static
1602xmlParserInputPtr
1603xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillard686d6b62000-01-03 11:08:02 +00001604 xmlParserCtxtPtr ctxt) {
1605 xmlParserInputPtr ret = NULL;
Daniel Veillard39c7d712000-09-10 16:14:55 +00001606
Daniel Veillardb96e6431999-08-29 21:02:19 +00001607#ifdef DEBUG_EXTERNAL_ENTITIES
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001608 xmlGenericError(xmlGenericErrorContext,
1609 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001610#endif
Daniel Veillard686d6b62000-01-03 11:08:02 +00001611 if (URL == NULL) {
1612 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001613 ctxt->sax->warning(ctxt,
1614 "failed to load external entity \"%s\"\n", ID);
Daniel Veillard686d6b62000-01-03 11:08:02 +00001615 return(NULL);
1616 }
1617 ret = xmlNewInputFromFile(ctxt, URL);
1618 if (ret == NULL) {
1619 if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001620 ctxt->sax->warning(ctxt,
1621 "failed to load external entity \"%s\"\n", URL);
Daniel Veillard686d6b62000-01-03 11:08:02 +00001622 }
1623 return(ret);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001624}
1625
1626static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1627 xmlDefaultExternalEntityLoader;
1628
1629/*
1630 * xmlSetExternalEntityLoader:
1631 * @f: the new entity resolver function
1632 *
1633 * Changes the defaultexternal entity resolver function for the application
1634 */
1635void
1636xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1637 xmlCurrentExternalEntityLoader = f;
1638}
1639
1640/*
1641 * xmlGetExternalEntityLoader:
1642 *
1643 * Get the default external entity resolver function for the application
1644 *
1645 * Returns the xmlExternalEntityLoader function pointer
1646 */
1647xmlExternalEntityLoader
1648xmlGetExternalEntityLoader(void) {
1649 return(xmlCurrentExternalEntityLoader);
1650}
1651
1652/*
1653 * xmlLoadExternalEntity:
1654 * @URL: the URL for the entity to load
1655 * @ID: the System ID for the entity to load
Daniel Veillard686d6b62000-01-03 11:08:02 +00001656 * @ctxt: the context in which the entity is called or NULL
Daniel Veillardb96e6431999-08-29 21:02:19 +00001657 *
1658 * Load an external entity, note that the use of this function for
1659 * unparsed entities may generate problems
1660 * TODO: a more generic External entitiy API must be designed
1661 *
1662 * Returns the xmlParserInputPtr or NULL
1663 */
1664xmlParserInputPtr
1665xmlLoadExternalEntity(const char *URL, const char *ID,
Daniel Veillard686d6b62000-01-03 11:08:02 +00001666 xmlParserCtxtPtr ctxt) {
1667 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001668}
1669