Annotation of XML/xmlIO.c, revision 1.41
1.1 daniel 1: /*
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
1.40 veillard 7: *
8: * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
1.1 daniel 9: */
10:
1.10 daniel 11: #ifdef WIN32
1.16 daniel 12: #include "win32config.h"
1.10 daniel 13: #else
1.12 daniel 14: #include "config.h"
1.10 daniel 15: #endif
16:
17: #include <stdio.h>
18: #include <string.h>
1.1 daniel 19:
1.10 daniel 20: #ifdef HAVE_SYS_TYPES_H
1.1 daniel 21: #include <sys/types.h>
1.10 daniel 22: #endif
23: #ifdef HAVE_SYS_STAT_H
1.1 daniel 24: #include <sys/stat.h>
1.10 daniel 25: #endif
26: #ifdef HAVE_FCNTL_H
1.1 daniel 27: #include <fcntl.h>
1.10 daniel 28: #endif
1.1 daniel 29: #ifdef HAVE_UNISTD_H
30: #include <unistd.h>
31: #endif
1.10 daniel 32: #ifdef HAVE_STDLIB_H
33: #include <stdlib.h>
34: #endif
1.1 daniel 35: #ifdef HAVE_ZLIB_H
36: #include <zlib.h>
37: #endif
38:
1.21 daniel 39: #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>
1.38 veillard 45: #include <libxml/xmlerror.h>
1.1 daniel 46:
1.40 veillard 47: #ifdef VMS
48: #define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
49: #define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
50: #endif
51:
1.2 daniel 52: /* #define VERBOSE_FAILURE */
1.5 daniel 53: /* #define DEBUG_EXTERNAL_ENTITIES */
1.28 daniel 54: /* #define DEBUG_INPUT */
1.1 daniel 55:
56: #ifdef DEBUG_INPUT
57: #define MINLEN 40
58: #else
59: #define MINLEN 4000
60: #endif
61:
1.22 daniel 62: /*
63: * Input I/O callback sets
64: */
65: typedef struct _xmlInputCallback {
66: xmlInputMatchCallback matchcallback;
67: xmlInputOpenCallback opencallback;
68: xmlInputReadCallback readcallback;
69: xmlInputCloseCallback closecallback;
70: } xmlInputCallback;
71:
1.23 daniel 72: #define MAX_INPUT_CALLBACK 15
1.22 daniel 73:
1.23 daniel 74: xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
75: int xmlInputCallbackNr = 0;
76: int xmlInputCallbackInitialized = 0;
77:
1.27 daniel 78: /*
79: * Output I/O callback sets
80: */
81: typedef struct _xmlOutputCallback {
82: xmlOutputMatchCallback matchcallback;
83: xmlOutputOpenCallback opencallback;
84: xmlOutputWriteCallback writecallback;
85: xmlOutputCloseCallback closecallback;
86: } xmlOutputCallback;
87:
88: #define MAX_OUTPUT_CALLBACK 15
89:
90: xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
91: int xmlOutputCallbackNr = 0;
92: int xmlOutputCallbackInitialized = 0;
93:
1.23 daniel 94: /************************************************************************
95: * *
96: * Standard I/O for file accesses *
97: * *
98: ************************************************************************/
1.22 daniel 99:
1.32 veillard 100: int
101: xmlNop(void) {
102: return(0);
103: }
104:
1.22 daniel 105: /**
1.23 daniel 106: * xmlFdMatch:
1.22 daniel 107: * @filename: the URI for matching
108: *
109: * input from file descriptor
110: *
111: * Returns 1 if matches, 0 otherwise
112: */
1.23 daniel 113: int
114: xmlFdMatch (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: */
127: void *
128: xmlFdOpen (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:
1.22 daniel 137: if (!strncmp(filename, "file://localhost", 16))
1.23 daniel 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: /**
1.28 daniel 156: * 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: */
164: void *
165: xmlFdOpenW (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: /**
1.23 daniel 189: * xmlFdRead:
190: * @context: the I/O context
191: * @buffer: where to drop data
1.27 daniel 192: * @len: number of bytes to read
1.23 daniel 193: *
194: * Read @len bytes to @buffer from the I/O channel.
195: *
196: * Returns the number of bytes written
197: */
198: int
199: xmlFdRead (void * context, char * buffer, int len) {
200: return(read((int) context, &buffer[0], len));
201: }
202:
203: /**
1.27 daniel 204: * 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: */
213: int
214: xmlFdWrite (void * context, const char * buffer, int len) {
215: return(write((int) context, &buffer[0], len));
216: }
217:
218: /**
1.23 daniel 219: * xmlFdClose:
220: * @context: the I/O context
221: *
222: * Close an I/O channel
223: */
224: void
225: xmlFdClose (void * context) {
226: close((int) context);
1.22 daniel 227: }
1.23 daniel 228:
1.22 daniel 229: /**
1.23 daniel 230: * xmlFileMatch:
1.22 daniel 231: * @filename: the URI for matching
232: *
1.23 daniel 233: * input from FILE *
1.22 daniel 234: *
235: * Returns 1 if matches, 0 otherwise
236: */
1.23 daniel 237: int
238: xmlFileMatch (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: */
251: void *
252: xmlFileOpen (const char *filename) {
1.22 daniel 253: const char *path = NULL;
1.23 daniel 254: FILE *fd;
255:
256: if (!strcmp(filename, "-")) {
257: fd = stdin;
258: return((void *) fd);
259: }
1.22 daniel 260:
261: if (!strncmp(filename, "file://localhost", 16))
262: path = &filename[16];
263: else if (!strncmp(filename, "file:///", 8))
1.23 daniel 264: path = &filename[8];
265: else
1.22 daniel 266: path = filename;
267: if (path == NULL)
1.23 daniel 268: return(NULL);
269:
1.22 daniel 270: #ifdef WIN32
1.23 daniel 271: fd = fopen(path, "rb");
1.22 daniel 272: #else
1.23 daniel 273: fd = fopen(path, "r");
274: #endif /* WIN32 */
275: return((void *) fd);
276: }
277:
278: /**
1.28 daniel 279: * 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: */
287: void *
288: xmlFileOpenW (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: /**
1.23 daniel 311: * 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: */
320: int
321: xmlFileRead (void * context, char * buffer, int len) {
322: return(fread(&buffer[0], 1, len, (FILE *) context));
323: }
324:
325: /**
1.27 daniel 326: * 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: */
335: int
336: xmlFileWrite (void * context, const char * buffer, int len) {
337: return(fwrite(&buffer[0], 1, len, (FILE *) context));
338: }
339:
340: /**
1.23 daniel 341: * xmlFileClose:
342: * @context: the I/O context
343: *
344: * Close an I/O channel
345: */
346: void
347: xmlFileClose (void * context) {
348: fclose((FILE *) context);
349: }
350:
1.37 veillard 351: /**
352: * xmlFileFlush:
353: * @context: the I/O context
354: *
355: * Flush an I/O channel
356: */
357: void
358: xmlFileFlush (void * context) {
359: fflush((FILE *) context);
360: }
361:
1.23 daniel 362: #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: */
376: int
377: xmlGzfileMatch (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: */
390: void *
391: xmlGzfileOpen (const char *filename) {
392: const char *path = NULL;
393: gzFile fd;
394:
395: if (!strcmp(filename, "-")) {
1.35 veillard 396: fd = gzdopen(fileno(stdin), "rb");
1.23 daniel 397: return((void *) fd);
398: }
399:
400: if (!strncmp(filename, "file://localhost", 16))
401: path = &filename[16];
402: else if (!strncmp(filename, "file:///", 8))
403: path = &filename[8];
404: else
405: path = filename;
406:
1.35 veillard 407: fd = gzopen(filename, "rb");
1.23 daniel 408: return((void *) fd);
409: }
410:
411: /**
1.28 daniel 412: * 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: */
421: void *
422: xmlGzfileOpenW (const char *filename, int compression) {
423: const char *path = NULL;
424: char mode[15];
425: gzFile fd;
426:
1.35 veillard 427: sprintf(mode, "wb%d", compression);
1.28 daniel 428: 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: /**
1.23 daniel 445: * 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: */
454: int
455: xmlGzfileRead (void * context, char * buffer, int len) {
456: return(gzread((gzFile) context, &buffer[0], len));
457: }
458:
459: /**
1.28 daniel 460: * 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: */
469: int
470: xmlGzfileWrite (void * context, const char * buffer, int len) {
471: return(gzwrite((gzFile) context, (char *) &buffer[0], len));
472: }
473:
474: /**
1.23 daniel 475: * xmlGzfileClose:
476: * @context: the I/O context
477: *
478: * Close a compressed I/O channel
479: */
480: void
481: xmlGzfileClose (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: */
500: int
501: xmlIOHTTPMatch (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: */
515: void *
516: xmlIOHTTPOpen (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: */
530: int
531: xmlIOHTTPRead(void * context, char * buffer, int len) {
532: return(xmlNanoHTTPRead(context, &buffer[0], len));
1.22 daniel 533: }
534:
1.23 daniel 535: /**
536: * xmlIOHTTPClose:
537: * @context: the I/O context
538: *
539: * Close an HTTP I/O channel
540: */
541: void
542: xmlIOHTTPClose (void * context) {
543: xmlNanoHTTPClose(context);
1.22 daniel 544: }
1.23 daniel 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: */
561: int
562: xmlIOFTPMatch (const char *filename) {
563: if (!strncmp(filename, "ftp://", 6))
564: return(1);
565: return(0);
1.22 daniel 566: }
567:
1.23 daniel 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: */
576: void *
577: xmlIOFTPOpen (const char *filename) {
578: return(xmlNanoFTPOpen(filename));
1.22 daniel 579: }
1.23 daniel 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: */
591: int
592: xmlIOFTPRead(void * context, char * buffer, int len) {
593: return(xmlNanoFTPRead(context, &buffer[0], len));
1.22 daniel 594: }
1.23 daniel 595:
596: /**
597: * xmlIOFTPClose:
598: * @context: the I/O context
599: *
600: * Close an FTP I/O channel
601: */
602: void
603: xmlIOFTPClose (void * context) {
604: xmlNanoFTPClose(context);
1.22 daniel 605: }
1.23 daniel 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: */
620: int
621: xmlRegisterInputCallbacks(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++);
1.22 daniel 632: }
633:
1.23 daniel 634: /**
1.27 daniel 635: * 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: */
645: int
646: xmlRegisterOutputCallbacks(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: /**
1.23 daniel 660: * xmlRegisterDefaultInputCallbacks:
661: *
662: * Registers the default compiled-in I/O handlers.
663: */
664: void
1.40 veillard 665: #ifdef VMS
666: xmlRegisterDefInputCallbacks
667: #else
668: xmlRegisterDefaultInputCallbacks
669: #endif
670: (void) {
1.34 veillard 671: if (xmlInputCallbackInitialized)
672: return;
673:
1.23 daniel 674: 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 */
1.34 veillard 690: xmlInputCallbackInitialized = 1;
1.23 daniel 691: }
1.22 daniel 692:
1.1 daniel 693: /**
1.27 daniel 694: * xmlRegisterDefaultOutputCallbacks:
695: *
696: * Registers the default compiled-in I/O handlers.
697: */
698: void
1.40 veillard 699: #ifdef VMS
700: xmlRegisterDefOutputCallbacks
701: #else
702: xmlRegisterDefaultOutputCallbacks
703: #endif
704: (void) {
1.34 veillard 705: if (xmlOutputCallbackInitialized)
706: return;
707:
1.28 daniel 708: xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1.27 daniel 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: **********************************/
1.34 veillard 732: xmlOutputCallbackInitialized = 1;
1.27 daniel 733: }
734:
735: /**
1.1 daniel 736: * 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: */
743: xmlParserInputBufferPtr
744: xmlAllocParserInputBuffer(xmlCharEncoding enc) {
745: xmlParserInputBufferPtr ret;
746:
1.8 daniel 747: ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1.1 daniel 748: if (ret == NULL) {
1.38 veillard 749: xmlGenericError(xmlGenericErrorContext,
750: "xmlAllocParserInputBuffer : out of memory!\n");
1.1 daniel 751: return(NULL);
752: }
1.3 veillard 753: memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1.1 daniel 754: ret->buffer = xmlBufferCreate();
1.17 daniel 755: if (ret->buffer == NULL) {
756: xmlFree(ret);
757: return(NULL);
758: }
759: ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1.1 daniel 760: ret->encoder = xmlGetCharEncodingHandler(enc);
1.26 daniel 761: if (ret->encoder != NULL)
762: ret->raw = xmlBufferCreate();
763: else
764: ret->raw = NULL;
1.23 daniel 765: ret->readcallback = NULL;
766: ret->closecallback = NULL;
767: ret->context = NULL;
1.1 daniel 768:
769: return(ret);
770: }
771:
772: /**
1.27 daniel 773: * 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: */
780: xmlOutputBufferPtr
781: xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
782: xmlOutputBufferPtr ret;
783:
784: ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
785: if (ret == NULL) {
1.38 veillard 786: xmlGenericError(xmlGenericErrorContext,
787: "xmlAllocOutputBuffer : out of memory!\n");
1.27 daniel 788: 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;
1.28 daniel 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;
1.27 daniel 806: ret->writecallback = NULL;
807: ret->closecallback = NULL;
808: ret->context = NULL;
1.28 daniel 809: ret->written = 0;
1.27 daniel 810:
811: return(ret);
812: }
813:
814: /**
1.1 daniel 815: * xmlFreeParserInputBuffer:
816: * @in: a buffered parser input
817: *
818: * Free up the memory used by a buffered parser input
819: */
820: void
821: xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1.26 daniel 822: if (in->raw) {
823: xmlBufferFree(in->raw);
824: in->raw = NULL;
825: }
1.25 daniel 826: if (in->encoder != NULL) {
827: xmlCharEncCloseFunc(in->encoder);
828: }
829: if (in->closecallback != NULL) {
830: in->closecallback(in->context);
831: }
1.1 daniel 832: if (in->buffer != NULL) {
833: xmlBufferFree(in->buffer);
834: in->buffer = NULL;
835: }
1.23 daniel 836:
1.3 veillard 837: memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
1.8 daniel 838: xmlFree(in);
1.1 daniel 839: }
840:
841: /**
1.28 daniel 842: * 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: */
850: int
851: xmlOutputBufferClose(xmlOutputBufferPtr out) {
852: int written;
853:
854: if (out == NULL)
855: return(-1);
1.39 veillard 856: if (out->writecallback != NULL)
857: xmlOutputBufferFlush(out);
1.28 daniel 858: 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: /**
1.1 daniel 880: * xmlParserInputBufferCreateFilename:
1.23 daniel 881: * @URI: a C string containing the URI or filename
1.1 daniel 882: * @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.
1.20 daniel 888: * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1.1 daniel 889: *
890: * Returns the new parser input or NULL
891: */
892: xmlParserInputBufferPtr
1.40 veillard 893: #ifdef VMS
894: xmlParserInputBufferCreateFname
895: #else
896: xmlParserInputBufferCreateFilename
897: #endif
898: (const char *URI, xmlCharEncoding enc) {
1.1 daniel 899: xmlParserInputBufferPtr ret;
1.23 daniel 900: int i;
901: void *context = NULL;
902:
903: if (xmlInputCallbackInitialized == 0)
904: xmlRegisterDefaultInputCallbacks();
1.1 daniel 905:
1.23 daniel 906: if (URI == NULL) return(NULL);
1.1 daniel 907:
1.23 daniel 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;
1.1 daniel 918: }
1.23 daniel 919: }
920: if (context == NULL) {
921: return(NULL);
1.1 daniel 922: }
1.20 daniel 923:
924: /*
925: * Allocate the Input buffer front-end.
1.1 daniel 926: */
927: ret = xmlAllocParserInputBuffer(enc);
928: if (ret != NULL) {
1.23 daniel 929: ret->context = context;
930: ret->readcallback = xmlInputCallbackTable[i].readcallback;
931: ret->closecallback = xmlInputCallbackTable[i].closecallback;
1.1 daniel 932: }
933: return(ret);
934: }
935:
936: /**
1.27 daniel 937: * xmlOutputBufferCreateFilename:
938: * @URI: a C string containing the URI or filename
939: * @encoder: the encoding converter or NULL
1.28 daniel 940: * @compression: the compression ration (0 none, 9 max).
1.27 daniel 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.
1.28 daniel 946: * TODO: currently if compression is set, the library only support
947: * writing to a local file.
1.27 daniel 948: *
949: * Returns the new output or NULL
950: */
951: xmlOutputBufferPtr
952: xmlOutputBufferCreateFilename(const char *URI,
1.28 daniel 953: xmlCharEncodingHandlerPtr encoder,
954: int compression) {
1.27 daniel 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:
1.28 daniel 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:
1.27 daniel 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) {
992: 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: /**
1.1 daniel 1008: * 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: */
1017: xmlParserInputBufferPtr
1018: xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1019: xmlParserInputBufferPtr ret;
1020:
1.23 daniel 1021: if (xmlInputCallbackInitialized == 0)
1022: xmlRegisterDefaultInputCallbacks();
1023:
1.1 daniel 1024: if (file == NULL) return(NULL);
1025:
1026: ret = xmlAllocParserInputBuffer(enc);
1.23 daniel 1027: if (ret != NULL) {
1028: ret->context = file;
1029: ret->readcallback = xmlFileRead;
1.37 veillard 1030: ret->closecallback = xmlFileFlush;
1.23 daniel 1031: }
1.1 daniel 1032:
1033: return(ret);
1034: }
1035:
1036: /**
1.27 daniel 1037: * 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: */
1046: xmlOutputBufferPtr
1047: xmlOutputBufferCreateFile(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;
1.37 veillard 1059: ret->closecallback = xmlFileFlush;
1.27 daniel 1060: }
1061:
1062: return(ret);
1063: }
1064:
1065: /**
1.1 daniel 1066: * 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: */
1075: xmlParserInputBufferPtr
1076: xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1077: xmlParserInputBufferPtr ret;
1078:
1079: if (fd < 0) return(NULL);
1080:
1081: ret = xmlAllocParserInputBuffer(enc);
1.23 daniel 1082: if (ret != NULL) {
1083: ret->context = (void *) fd;
1084: ret->readcallback = xmlFdRead;
1085: ret->closecallback = xmlFdClose;
1086: }
1.1 daniel 1087:
1088: return(ret);
1089: }
1090:
1091: /**
1.31 veillard 1092: * 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
1098: * from a file descriptor
1099: *
1100: * Returns the new parser input or NULL
1101: */
1102: xmlParserInputBufferPtr
1103: xmlParserInputBufferCreateMem(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;
1.32 veillard 1112: ret->readcallback = (xmlInputReadCallback) xmlNop;
1.31 veillard 1113: ret->closecallback = NULL;
1114: xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1115: }
1116:
1117: return(ret);
1118: }
1119:
1120: /**
1.27 daniel 1121: * 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: */
1130: xmlOutputBufferPtr
1131: xmlOutputBufferCreateFd(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: /**
1.24 daniel 1147: * 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
1.27 daniel 1154: * from an I/O handler
1.24 daniel 1155: *
1156: * Returns the new parser input or NULL
1157: */
1158: xmlParserInputBufferPtr
1159: xmlParserInputBufferCreateIO(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: /**
1.27 daniel 1176: * 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: */
1187: xmlOutputBufferPtr
1188: xmlOutputBufferCreateIO(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: /**
1.14 daniel 1206: * xmlParserInputBufferPush:
1207: * @in: a buffered parser input
1.27 daniel 1208: * @len: the size in bytes of the array.
1.14 daniel 1209: * @buf: an char array
1210: *
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: */
1218: int
1.38 veillard 1219: xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1220: int len, const char *buf) {
1.14 daniel 1221: int nbchars = 0;
1222:
1223: if (len < 0) return(0);
1224: if (in->encoder != NULL) {
1.26 daniel 1225: /*
1226: * Store the data in the incoming raw buffer
1227: */
1228: if (in->raw == NULL) {
1229: in->raw = xmlBufferCreate();
1230: }
1231: xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1.14 daniel 1232:
1233: /*
1.26 daniel 1234: * convert as much as possible to the parser reading buffer.
1.14 daniel 1235: */
1.26 daniel 1236: nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1.20 daniel 1237: if (nbchars < 0) {
1.38 veillard 1238: xmlGenericError(xmlGenericErrorContext,
1239: "xmlParserInputBufferPush: encoder error\n");
1.20 daniel 1240: return(-1);
1241: }
1.14 daniel 1242: } else {
1243: nbchars = len;
1.17 daniel 1244: xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1.14 daniel 1245: }
1246: #ifdef DEBUG_INPUT
1.38 veillard 1247: xmlGenericError(xmlGenericErrorContext,
1248: "I/O: pushed %d chars, buffer %d/%d\n",
1.14 daniel 1249: nbchars, in->buffer->use, in->buffer->size);
1250: #endif
1251: return(nbchars);
1252: }
1253:
1254: /**
1.1 daniel 1255: * 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
1.14 daniel 1261: * This routine is used when operating the parser in normal (pull) mode
1.26 daniel 1262: *
1263: * TODO: one should be able to remove one extra copy by copying directy
1264: * onto in->buffer or in->raw
1.1 daniel 1265: *
1266: * Returns the number of chars read and stored in the buffer, or -1
1267: * in case of error.
1268: */
1269: int
1270: xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1271: char *buffer = NULL;
1272: 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) {
1.38 veillard 1280: xmlGenericError(xmlGenericErrorContext,
1281: "xmlParserInputBufferGrow : buffer full !\n");
1.1 daniel 1282: return(0);
1283: }
1284: if (len > buffree)
1285: len = buffree;
1286:
1.30 veillard 1287: buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
1.1 daniel 1288: if (buffer == NULL) {
1.38 veillard 1289: xmlGenericError(xmlGenericErrorContext,
1290: "xmlParserInputBufferGrow : out of memory !\n");
1.1 daniel 1291: return(-1);
1292: }
1.23 daniel 1293:
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);
1.1 daniel 1299: } else {
1.38 veillard 1300: xmlGenericError(xmlGenericErrorContext,
1301: "xmlParserInputBufferGrow : no input !\n");
1.8 daniel 1302: xmlFree(buffer);
1.1 daniel 1303: return(-1);
1304: }
1305: if (res < 0) {
1306: perror ("read error");
1.8 daniel 1307: xmlFree(buffer);
1.1 daniel 1308: return(-1);
1309: }
1.29 daniel 1310: len = res;
1.1 daniel 1311: if (in->encoder != NULL) {
1.26 daniel 1312: /*
1313: * Store the data in the incoming raw buffer
1314: */
1315: if (in->raw == NULL) {
1316: in->raw = xmlBufferCreate();
1.1 daniel 1317: }
1.26 daniel 1318: xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
1.20 daniel 1319:
1320: /*
1.26 daniel 1321: * convert as much as possible to the parser reading buffer.
1.20 daniel 1322: */
1.26 daniel 1323: nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1324: if (nbchars < 0) {
1.38 veillard 1325: xmlGenericError(xmlGenericErrorContext,
1326: "xmlParserInputBufferGrow: encoder error\n");
1.26 daniel 1327: return(-1);
1.20 daniel 1328: }
1.1 daniel 1329: } else {
1.29 daniel 1330: nbchars = len;
1.3 veillard 1331: buffer[nbchars] = 0;
1.13 daniel 1332: xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
1.1 daniel 1333: }
1334: #ifdef DEBUG_INPUT
1.38 veillard 1335: xmlGenericError(xmlGenericErrorContext,
1336: "I/O: read %d chars, buffer %d/%d\n",
1.1 daniel 1337: nbchars, in->buffer->use, in->buffer->size);
1338: #endif
1.8 daniel 1339: xmlFree(buffer);
1.1 daniel 1340: 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: */
1355: int
1356: xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1357: /* xmlBufferEmpty(in->buffer); */
1.23 daniel 1358: if (in->readcallback != NULL)
1.17 daniel 1359: return(xmlParserInputBufferGrow(in, len));
1360: else
1.27 daniel 1361: 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: */
1378: int
1379: xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
1380: int nbchars = 0, ret;
1381:
1382: if (len < 0) return(0);
1383:
1384: /*
1385: * first handle encoding stuff.
1386: */
1387: if (out->encoder != NULL) {
1388: /*
1389: * Store the data in the incoming raw buffer
1390: */
1.28 daniel 1391: if (out->conv == NULL) {
1392: out->conv = xmlBufferCreate();
1.27 daniel 1393: }
1.28 daniel 1394: xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1.27 daniel 1395:
1.28 daniel 1396: if (out->buffer->use < MINLEN)
1.27 daniel 1397: return(0);
1398:
1399: /*
1400: * convert as much as possible to the parser reading buffer.
1401: */
1.28 daniel 1402: nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1.27 daniel 1403: if (nbchars < 0) {
1.38 veillard 1404: xmlGenericError(xmlGenericErrorContext,
1405: "xmlOutputBufferWrite: encoder error\n");
1.27 daniel 1406: return(-1);
1407: }
1.28 daniel 1408: nbchars = out->conv->use;
1.27 daniel 1409: } else {
1410: xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1.28 daniel 1411: nbchars = out->buffer->use;
1.27 daniel 1412: }
1413: if (nbchars < MINLEN)
1414: return(0);
1415:
1.41 ! veillard 1416: if (!out->writecallback)
! 1417: return(nbchars);
! 1418:
1.27 daniel 1419: /*
1420: * second write the stuff to the I/O channel
1421: */
1.28 daniel 1422: if (out->encoder != NULL) {
1423: ret = out->writecallback(out->context,
1424: (const char *)out->conv->content, nbchars);
1425: if (ret >= 0)
1426: xmlBufferShrink(out->conv, nbchars);
1427: } else {
1428: ret = out->writecallback(out->context,
1.27 daniel 1429: (const char *)out->buffer->content, nbchars);
1.28 daniel 1430: if (ret >= 0)
1431: xmlBufferShrink(out->buffer, nbchars);
1432: }
1.27 daniel 1433: if (ret < 0) {
1.38 veillard 1434: xmlGenericError(xmlGenericErrorContext,
1435: "I/O: error %d writing %d bytes\n", ret, nbchars);
1.27 daniel 1436: return(ret);
1437: }
1.28 daniel 1438: out->written += ret;
1.27 daniel 1439:
1440: #ifdef DEBUG_INPUT
1.38 veillard 1441: xmlGenericError(xmlGenericErrorContext,
1442: "I/O: wrote %d chars\n", ret);
1.27 daniel 1443: #endif
1444: return(nbchars);
1.28 daniel 1445: }
1446:
1447: /**
1448: * xmlOutputBufferWriteString:
1449: * @out: a buffered parser output
1450: * @str: a zero terminated C string
1451: *
1452: * Write the content of the string in the output I/O buffer
1453: * This routine handle the I18N transcoding from internal UTF-8
1454: * The buffer is lossless, i.e. will store in case of partial
1455: * or delayed writes.
1456: *
1457: * Returns the number of chars immediately written, or -1
1458: * in case of error.
1459: */
1460: int
1461: xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
1462: int len;
1463:
1464: if (str == NULL)
1465: return(-1);
1466: len = strlen(str);
1467:
1468: if (len > 0)
1469: return(xmlOutputBufferWrite(out, len, str));
1470: return(len);
1471: }
1472:
1473: /**
1474: * xmlOutputBufferFlush:
1475: * @out: a buffered output
1476: *
1477: * flushes the output I/O channel
1478: *
1479: * Returns the number of byte written or -1 in case of error.
1480: */
1481: int
1482: xmlOutputBufferFlush(xmlOutputBufferPtr out) {
1.41 ! veillard 1483: int nbchars = 0, ret = 0;
1.28 daniel 1484:
1485: /*
1486: * first handle encoding stuff.
1487: */
1488: if ((out->conv != NULL) && (out->encoder != NULL)) {
1489: /*
1490: * convert as much as possible to the parser reading buffer.
1491: */
1492: nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1493: if (nbchars < 0) {
1.38 veillard 1494: xmlGenericError(xmlGenericErrorContext,
1495: "xmlOutputBufferWrite: encoder error\n");
1.28 daniel 1496: return(-1);
1497: }
1498: }
1499:
1500: /*
1501: * second flush the stuff to the I/O channel
1502: */
1.41 ! veillard 1503: if ((out->conv != NULL) && (out->encoder != NULL) &&
! 1504: (out->writecallback != NULL)) {
1.28 daniel 1505: ret = out->writecallback(out->context,
1506: (const char *)out->conv->content, out->conv->use);
1507: if (ret >= 0)
1508: xmlBufferShrink(out->conv, ret);
1.41 ! veillard 1509: } else if (out->writecallback != NULL) {
1.28 daniel 1510: ret = out->writecallback(out->context,
1511: (const char *)out->buffer->content, out->buffer->use);
1512: if (ret >= 0)
1513: xmlBufferShrink(out->buffer, ret);
1514: }
1515: if (ret < 0) {
1.38 veillard 1516: xmlGenericError(xmlGenericErrorContext,
1517: "I/O: error %d flushing %d bytes\n", ret, nbchars);
1.28 daniel 1518: return(ret);
1519: }
1520: out->written += ret;
1521:
1522: #ifdef DEBUG_INPUT
1.38 veillard 1523: xmlGenericError(xmlGenericErrorContext,
1524: "I/O: flushed %d chars\n", ret);
1.28 daniel 1525: #endif
1526: return(ret);
1.4 daniel 1527: }
1528:
1529: /*
1530: * xmlParserGetDirectory:
1531: * @filename: the path to a file
1532: *
1533: * lookup the directory for that file
1534: *
1535: * Returns a new allocated string containing the directory, or NULL.
1536: */
1537: char *
1538: xmlParserGetDirectory(const char *filename) {
1539: char *ret = NULL;
1540: char dir[1024];
1541: char *cur;
1542: char sep = '/';
1.23 daniel 1543:
1544: if (xmlInputCallbackInitialized == 0)
1545: xmlRegisterDefaultInputCallbacks();
1.4 daniel 1546:
1547: if (filename == NULL) return(NULL);
1548: #ifdef WIN32
1549: sep = '\\';
1550: #endif
1551:
1552: strncpy(dir, filename, 1023);
1553: dir[1023] = 0;
1554: cur = &dir[strlen(dir)];
1555: while (cur > dir) {
1556: if (*cur == sep) break;
1557: cur --;
1558: }
1559: if (*cur == sep) {
1560: if (cur == dir) dir[1] = 0;
1561: else *cur = 0;
1.8 daniel 1562: ret = xmlMemStrdup(dir);
1.4 daniel 1563: } else {
1564: if (getcwd(dir, 1024) != NULL) {
1565: dir[1023] = 0;
1.8 daniel 1566: ret = xmlMemStrdup(dir);
1.4 daniel 1567: }
1568: }
1569: return(ret);
1.5 daniel 1570: }
1571:
1572: /****************************************************************
1573: * *
1574: * External entities loading *
1575: * *
1576: ****************************************************************/
1577:
1578: /*
1579: * xmlDefaultExternalEntityLoader:
1580: * @URL: the URL for the entity to load
1581: * @ID: the System ID for the entity to load
1.18 daniel 1582: * @ctxt: the context in which the entity is called or NULL
1.5 daniel 1583: *
1584: * By default we don't load external entitites, yet.
1585: *
1586: * Returns a new allocated xmlParserInputPtr, or NULL.
1587: */
1588: static
1589: xmlParserInputPtr
1590: xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
1.18 daniel 1591: xmlParserCtxtPtr ctxt) {
1592: xmlParserInputPtr ret = NULL;
1.33 veillard 1593:
1.5 daniel 1594: #ifdef DEBUG_EXTERNAL_ENTITIES
1.38 veillard 1595: xmlGenericError(xmlGenericErrorContext,
1596: "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
1.5 daniel 1597: #endif
1.18 daniel 1598: if (URL == NULL) {
1599: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1.38 veillard 1600: ctxt->sax->warning(ctxt,
1601: "failed to load external entity \"%s\"\n", ID);
1.18 daniel 1602: return(NULL);
1603: }
1604: ret = xmlNewInputFromFile(ctxt, URL);
1605: if (ret == NULL) {
1606: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1.38 veillard 1607: ctxt->sax->warning(ctxt,
1608: "failed to load external entity \"%s\"\n", URL);
1.18 daniel 1609: }
1610: return(ret);
1.5 daniel 1611: }
1612:
1613: static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1614: xmlDefaultExternalEntityLoader;
1615:
1616: /*
1617: * xmlSetExternalEntityLoader:
1618: * @f: the new entity resolver function
1619: *
1620: * Changes the defaultexternal entity resolver function for the application
1621: */
1622: void
1623: xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1624: xmlCurrentExternalEntityLoader = f;
1625: }
1626:
1627: /*
1628: * xmlGetExternalEntityLoader:
1629: *
1630: * Get the default external entity resolver function for the application
1631: *
1632: * Returns the xmlExternalEntityLoader function pointer
1633: */
1634: xmlExternalEntityLoader
1635: xmlGetExternalEntityLoader(void) {
1636: return(xmlCurrentExternalEntityLoader);
1637: }
1638:
1639: /*
1640: * xmlLoadExternalEntity:
1641: * @URL: the URL for the entity to load
1642: * @ID: the System ID for the entity to load
1.18 daniel 1643: * @ctxt: the context in which the entity is called or NULL
1.5 daniel 1644: *
1645: * Load an external entity, note that the use of this function for
1646: * unparsed entities may generate problems
1.6 daniel 1647: * TODO: a more generic External entitiy API must be designed
1.5 daniel 1648: *
1649: * Returns the xmlParserInputPtr or NULL
1650: */
1651: xmlParserInputPtr
1652: xmlLoadExternalEntity(const char *URL, const char *ID,
1.18 daniel 1653: xmlParserCtxtPtr ctxt) {
1654: return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
1.1 daniel 1655: }
1656:
Webmaster