Annotation of XML/xmlIO.c, revision 1.39
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
7: */
8:
1.10 daniel 9: #ifdef WIN32
1.16 daniel 10: #include "win32config.h"
1.10 daniel 11: #else
1.12 daniel 12: #include "config.h"
1.10 daniel 13: #endif
14:
15: #include <stdio.h>
16: #include <string.h>
1.1 daniel 17:
1.10 daniel 18: #ifdef HAVE_SYS_TYPES_H
1.1 daniel 19: #include <sys/types.h>
1.10 daniel 20: #endif
21: #ifdef HAVE_SYS_STAT_H
1.1 daniel 22: #include <sys/stat.h>
1.10 daniel 23: #endif
24: #ifdef HAVE_FCNTL_H
1.1 daniel 25: #include <fcntl.h>
1.10 daniel 26: #endif
1.1 daniel 27: #ifdef HAVE_UNISTD_H
28: #include <unistd.h>
29: #endif
1.10 daniel 30: #ifdef HAVE_STDLIB_H
31: #include <stdlib.h>
32: #endif
1.1 daniel 33: #ifdef HAVE_ZLIB_H
34: #include <zlib.h>
35: #endif
36:
1.21 daniel 37: #include <libxml/xmlmemory.h>
38: #include <libxml/parser.h>
39: #include <libxml/parserInternals.h>
40: #include <libxml/xmlIO.h>
41: #include <libxml/nanohttp.h>
42: #include <libxml/nanoftp.h>
1.38 veillard 43: #include <libxml/xmlerror.h>
1.1 daniel 44:
1.2 daniel 45: /* #define VERBOSE_FAILURE */
1.5 daniel 46: /* #define DEBUG_EXTERNAL_ENTITIES */
1.28 daniel 47: /* #define DEBUG_INPUT */
1.1 daniel 48:
49: #ifdef DEBUG_INPUT
50: #define MINLEN 40
51: #else
52: #define MINLEN 4000
53: #endif
54:
1.22 daniel 55: /*
56: * Input I/O callback sets
57: */
58: typedef struct _xmlInputCallback {
59: xmlInputMatchCallback matchcallback;
60: xmlInputOpenCallback opencallback;
61: xmlInputReadCallback readcallback;
62: xmlInputCloseCallback closecallback;
63: } xmlInputCallback;
64:
1.23 daniel 65: #define MAX_INPUT_CALLBACK 15
1.22 daniel 66:
1.23 daniel 67: xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
68: int xmlInputCallbackNr = 0;
69: int xmlInputCallbackInitialized = 0;
70:
1.27 daniel 71: /*
72: * Output I/O callback sets
73: */
74: typedef struct _xmlOutputCallback {
75: xmlOutputMatchCallback matchcallback;
76: xmlOutputOpenCallback opencallback;
77: xmlOutputWriteCallback writecallback;
78: xmlOutputCloseCallback closecallback;
79: } xmlOutputCallback;
80:
81: #define MAX_OUTPUT_CALLBACK 15
82:
83: xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
84: int xmlOutputCallbackNr = 0;
85: int xmlOutputCallbackInitialized = 0;
86:
1.23 daniel 87: /************************************************************************
88: * *
89: * Standard I/O for file accesses *
90: * *
91: ************************************************************************/
1.22 daniel 92:
1.32 veillard 93: int
94: xmlNop(void) {
95: return(0);
96: }
97:
1.22 daniel 98: /**
1.23 daniel 99: * xmlFdMatch:
1.22 daniel 100: * @filename: the URI for matching
101: *
102: * input from file descriptor
103: *
104: * Returns 1 if matches, 0 otherwise
105: */
1.23 daniel 106: int
107: xmlFdMatch (const char *filename) {
108: return(1);
109: }
110:
111: /**
112: * xmlFdOpen:
113: * @filename: the URI for matching
114: *
115: * input from file descriptor, supports compressed input
116: * if @filename is " " then the standard input is used
117: *
118: * Returns an I/O context or NULL in case of error
119: */
120: void *
121: xmlFdOpen (const char *filename) {
122: const char *path = NULL;
123: int fd;
124:
125: if (!strcmp(filename, "-")) {
126: fd = 0;
127: return((void *) fd);
128: }
129:
1.22 daniel 130: if (!strncmp(filename, "file://localhost", 16))
1.23 daniel 131: path = &filename[16];
132: else if (!strncmp(filename, "file:///", 8))
133: path = &filename[8];
134: else if (filename[0] == '/')
135: path = filename;
136: if (path == NULL)
137: return(NULL);
138:
139: #ifdef WIN32
140: fd = _open (filename, O_RDONLY | _O_BINARY);
141: #else
142: fd = open (filename, O_RDONLY);
143: #endif
144:
145: return((void *) fd);
146: }
147:
148: /**
1.28 daniel 149: * xmlFdOpenW:
150: * @filename: the URI for matching
151: *
152: * input from file descriptor,
153: * if @filename is "-" then the standard output is used
154: *
155: * Returns an I/O context or NULL in case of error
156: */
157: void *
158: xmlFdOpenW (const char *filename) {
159: const char *path = NULL;
160: int fd;
161:
162: if (!strcmp(filename, "-")) {
163: fd = 1;
164: return((void *) fd);
165: }
166:
167: if (!strncmp(filename, "file://localhost", 16))
168: path = &filename[16];
169: else if (!strncmp(filename, "file:///", 8))
170: path = &filename[8];
171: else if (filename[0] == '/')
172: path = filename;
173: if (path == NULL)
174: return(NULL);
175:
176: fd = open (filename, O_WRONLY);
177:
178: return((void *) fd);
179: }
180:
181: /**
1.23 daniel 182: * xmlFdRead:
183: * @context: the I/O context
184: * @buffer: where to drop data
1.27 daniel 185: * @len: number of bytes to read
1.23 daniel 186: *
187: * Read @len bytes to @buffer from the I/O channel.
188: *
189: * Returns the number of bytes written
190: */
191: int
192: xmlFdRead (void * context, char * buffer, int len) {
193: return(read((int) context, &buffer[0], len));
194: }
195:
196: /**
1.27 daniel 197: * xmlFdWrite:
198: * @context: the I/O context
199: * @buffer: where to get data
200: * @len: number of bytes to write
201: *
202: * Write @len bytes from @buffer to the I/O channel.
203: *
204: * Returns the number of bytes written
205: */
206: int
207: xmlFdWrite (void * context, const char * buffer, int len) {
208: return(write((int) context, &buffer[0], len));
209: }
210:
211: /**
1.23 daniel 212: * xmlFdClose:
213: * @context: the I/O context
214: *
215: * Close an I/O channel
216: */
217: void
218: xmlFdClose (void * context) {
219: close((int) context);
1.22 daniel 220: }
1.23 daniel 221:
1.22 daniel 222: /**
1.23 daniel 223: * xmlFileMatch:
1.22 daniel 224: * @filename: the URI for matching
225: *
1.23 daniel 226: * input from FILE *
1.22 daniel 227: *
228: * Returns 1 if matches, 0 otherwise
229: */
1.23 daniel 230: int
231: xmlFileMatch (const char *filename) {
232: return(1);
233: }
234:
235: /**
236: * xmlFileOpen:
237: * @filename: the URI for matching
238: *
239: * input from FILE *, supports compressed input
240: * if @filename is " " then the standard input is used
241: *
242: * Returns an I/O context or NULL in case of error
243: */
244: void *
245: xmlFileOpen (const char *filename) {
1.22 daniel 246: const char *path = NULL;
1.23 daniel 247: FILE *fd;
248:
249: if (!strcmp(filename, "-")) {
250: fd = stdin;
251: return((void *) fd);
252: }
1.22 daniel 253:
254: if (!strncmp(filename, "file://localhost", 16))
255: path = &filename[16];
256: else if (!strncmp(filename, "file:///", 8))
1.23 daniel 257: path = &filename[8];
258: else
1.22 daniel 259: path = filename;
260: if (path == NULL)
1.23 daniel 261: return(NULL);
262:
1.22 daniel 263: #ifdef WIN32
1.23 daniel 264: fd = fopen(path, "rb");
1.22 daniel 265: #else
1.23 daniel 266: fd = fopen(path, "r");
267: #endif /* WIN32 */
268: return((void *) fd);
269: }
270:
271: /**
1.28 daniel 272: * xmlFileOpenW:
273: * @filename: the URI for matching
274: *
275: * output to from FILE *,
276: * if @filename is "-" then the standard output is used
277: *
278: * Returns an I/O context or NULL in case of error
279: */
280: void *
281: xmlFileOpenW (const char *filename) {
282: const char *path = NULL;
283: FILE *fd;
284:
285: if (!strcmp(filename, "-")) {
286: fd = stdout;
287: return((void *) fd);
288: }
289:
290: if (!strncmp(filename, "file://localhost", 16))
291: path = &filename[16];
292: else if (!strncmp(filename, "file:///", 8))
293: path = &filename[8];
294: else
295: path = filename;
296: if (path == NULL)
297: return(NULL);
298:
299: fd = fopen(path, "w");
300: return((void *) fd);
301: }
302:
303: /**
1.23 daniel 304: * xmlFileRead:
305: * @context: the I/O context
306: * @buffer: where to drop data
307: * @len: number of bytes to write
308: *
309: * Read @len bytes to @buffer from the I/O channel.
310: *
311: * Returns the number of bytes written
312: */
313: int
314: xmlFileRead (void * context, char * buffer, int len) {
315: return(fread(&buffer[0], 1, len, (FILE *) context));
316: }
317:
318: /**
1.27 daniel 319: * xmlFileWrite:
320: * @context: the I/O context
321: * @buffer: where to drop data
322: * @len: number of bytes to write
323: *
324: * Write @len bytes from @buffer to the I/O channel.
325: *
326: * Returns the number of bytes written
327: */
328: int
329: xmlFileWrite (void * context, const char * buffer, int len) {
330: return(fwrite(&buffer[0], 1, len, (FILE *) context));
331: }
332:
333: /**
1.23 daniel 334: * xmlFileClose:
335: * @context: the I/O context
336: *
337: * Close an I/O channel
338: */
339: void
340: xmlFileClose (void * context) {
341: fclose((FILE *) context);
342: }
343:
1.37 veillard 344: /**
345: * xmlFileFlush:
346: * @context: the I/O context
347: *
348: * Flush an I/O channel
349: */
350: void
351: xmlFileFlush (void * context) {
352: fflush((FILE *) context);
353: }
354:
1.23 daniel 355: #ifdef HAVE_ZLIB_H
356: /************************************************************************
357: * *
358: * I/O for compressed file accesses *
359: * *
360: ************************************************************************/
361: /**
362: * xmlGzfileMatch:
363: * @filename: the URI for matching
364: *
365: * input from compressed file test
366: *
367: * Returns 1 if matches, 0 otherwise
368: */
369: int
370: xmlGzfileMatch (const char *filename) {
371: return(1);
372: }
373:
374: /**
375: * xmlGzfileOpen:
376: * @filename: the URI for matching
377: *
378: * input from compressed file open
379: * if @filename is " " then the standard input is used
380: *
381: * Returns an I/O context or NULL in case of error
382: */
383: void *
384: xmlGzfileOpen (const char *filename) {
385: const char *path = NULL;
386: gzFile fd;
387:
388: if (!strcmp(filename, "-")) {
1.35 veillard 389: fd = gzdopen(fileno(stdin), "rb");
1.23 daniel 390: return((void *) fd);
391: }
392:
393: if (!strncmp(filename, "file://localhost", 16))
394: path = &filename[16];
395: else if (!strncmp(filename, "file:///", 8))
396: path = &filename[8];
397: else
398: path = filename;
399:
1.35 veillard 400: fd = gzopen(filename, "rb");
1.23 daniel 401: return((void *) fd);
402: }
403:
404: /**
1.28 daniel 405: * xmlGzfileOpenW:
406: * @filename: the URI for matching
407: * @compression: the compression factor (0 - 9 included)
408: *
409: * input from compressed file open
410: * if @filename is " " then the standard input is used
411: *
412: * Returns an I/O context or NULL in case of error
413: */
414: void *
415: xmlGzfileOpenW (const char *filename, int compression) {
416: const char *path = NULL;
417: char mode[15];
418: gzFile fd;
419:
1.35 veillard 420: sprintf(mode, "wb%d", compression);
1.28 daniel 421: if (!strcmp(filename, "-")) {
422: fd = gzdopen(1, mode);
423: return((void *) fd);
424: }
425:
426: if (!strncmp(filename, "file://localhost", 16))
427: path = &filename[16];
428: else if (!strncmp(filename, "file:///", 8))
429: path = &filename[8];
430: else
431: path = filename;
432:
433: fd = gzopen(filename, mode);
434: return((void *) fd);
435: }
436:
437: /**
1.23 daniel 438: * xmlGzfileRead:
439: * @context: the I/O context
440: * @buffer: where to drop data
441: * @len: number of bytes to write
442: *
443: * Read @len bytes to @buffer from the compressed I/O channel.
444: *
445: * Returns the number of bytes written
446: */
447: int
448: xmlGzfileRead (void * context, char * buffer, int len) {
449: return(gzread((gzFile) context, &buffer[0], len));
450: }
451:
452: /**
1.28 daniel 453: * xmlGzfileWrite:
454: * @context: the I/O context
455: * @buffer: where to drop data
456: * @len: number of bytes to write
457: *
458: * Write @len bytes from @buffer to the compressed I/O channel.
459: *
460: * Returns the number of bytes written
461: */
462: int
463: xmlGzfileWrite (void * context, const char * buffer, int len) {
464: return(gzwrite((gzFile) context, (char *) &buffer[0], len));
465: }
466:
467: /**
1.23 daniel 468: * xmlGzfileClose:
469: * @context: the I/O context
470: *
471: * Close a compressed I/O channel
472: */
473: void
474: xmlGzfileClose (void * context) {
475: gzclose((gzFile) context);
476: }
477: #endif /* HAVE_ZLIB_H */
478:
479: #ifdef LIBXML_HTTP_ENABLED
480: /************************************************************************
481: * *
482: * I/O for HTTP file accesses *
483: * *
484: ************************************************************************/
485: /**
486: * xmlIOHTTPMatch:
487: * @filename: the URI for matching
488: *
489: * check if the URI matches an HTTP one
490: *
491: * Returns 1 if matches, 0 otherwise
492: */
493: int
494: xmlIOHTTPMatch (const char *filename) {
495: if (!strncmp(filename, "http://", 7))
496: return(1);
497: return(0);
498: }
499:
500: /**
501: * xmlIOHTTPOpen:
502: * @filename: the URI for matching
503: *
504: * open an HTTP I/O channel
505: *
506: * Returns an I/O context or NULL in case of error
507: */
508: void *
509: xmlIOHTTPOpen (const char *filename) {
510: return(xmlNanoHTTPOpen(filename, NULL));
511: }
512:
513: /**
514: * xmlIOHTTPRead:
515: * @context: the I/O context
516: * @buffer: where to drop data
517: * @len: number of bytes to write
518: *
519: * Read @len bytes to @buffer from the I/O channel.
520: *
521: * Returns the number of bytes written
522: */
523: int
524: xmlIOHTTPRead(void * context, char * buffer, int len) {
525: return(xmlNanoHTTPRead(context, &buffer[0], len));
1.22 daniel 526: }
527:
1.23 daniel 528: /**
529: * xmlIOHTTPClose:
530: * @context: the I/O context
531: *
532: * Close an HTTP I/O channel
533: */
534: void
535: xmlIOHTTPClose (void * context) {
536: xmlNanoHTTPClose(context);
1.22 daniel 537: }
1.23 daniel 538: #endif /* LIBXML_HTTP_ENABLED */
539:
540: #ifdef LIBXML_FTP_ENABLED
541: /************************************************************************
542: * *
543: * I/O for FTP file accesses *
544: * *
545: ************************************************************************/
546: /**
547: * xmlIOFTPMatch:
548: * @filename: the URI for matching
549: *
550: * check if the URI matches an FTP one
551: *
552: * Returns 1 if matches, 0 otherwise
553: */
554: int
555: xmlIOFTPMatch (const char *filename) {
556: if (!strncmp(filename, "ftp://", 6))
557: return(1);
558: return(0);
1.22 daniel 559: }
560:
1.23 daniel 561: /**
562: * xmlIOFTPOpen:
563: * @filename: the URI for matching
564: *
565: * open an FTP I/O channel
566: *
567: * Returns an I/O context or NULL in case of error
568: */
569: void *
570: xmlIOFTPOpen (const char *filename) {
571: return(xmlNanoFTPOpen(filename));
1.22 daniel 572: }
1.23 daniel 573:
574: /**
575: * xmlIOFTPRead:
576: * @context: the I/O context
577: * @buffer: where to drop data
578: * @len: number of bytes to write
579: *
580: * Read @len bytes to @buffer from the I/O channel.
581: *
582: * Returns the number of bytes written
583: */
584: int
585: xmlIOFTPRead(void * context, char * buffer, int len) {
586: return(xmlNanoFTPRead(context, &buffer[0], len));
1.22 daniel 587: }
1.23 daniel 588:
589: /**
590: * xmlIOFTPClose:
591: * @context: the I/O context
592: *
593: * Close an FTP I/O channel
594: */
595: void
596: xmlIOFTPClose (void * context) {
597: xmlNanoFTPClose(context);
1.22 daniel 598: }
1.23 daniel 599: #endif /* LIBXML_FTP_ENABLED */
600:
601:
602: /**
603: * xmlRegisterInputCallbacks:
604: * @match: the xmlInputMatchCallback
605: * @open: the xmlInputOpenCallback
606: * @read: the xmlInputReadCallback
607: * @close: the xmlInputCloseCallback
608: *
609: * Register a new set of I/O callback for handling parser input.
610: *
611: * Returns the registered handler number or -1 in case of error
612: */
613: int
614: xmlRegisterInputCallbacks(xmlInputMatchCallback match,
615: xmlInputOpenCallback open, xmlInputReadCallback read,
616: xmlInputCloseCallback close) {
617: if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
618: return(-1);
619: }
620: xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match;
621: xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open;
622: xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read;
623: xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close;
624: return(xmlInputCallbackNr++);
1.22 daniel 625: }
626:
1.23 daniel 627: /**
1.27 daniel 628: * xmlRegisterOutputCallbacks:
629: * @match: the xmlOutputMatchCallback
630: * @open: the xmlOutputOpenCallback
631: * @write: the xmlOutputWriteCallback
632: * @close: the xmlOutputCloseCallback
633: *
634: * Register a new set of I/O callback for handling output.
635: *
636: * Returns the registered handler number or -1 in case of error
637: */
638: int
639: xmlRegisterOutputCallbacks(xmlOutputMatchCallback match,
640: xmlOutputOpenCallback open, xmlOutputWriteCallback write,
641: xmlOutputCloseCallback close) {
642: if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
643: return(-1);
644: }
645: xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = match;
646: xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = open;
647: xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = write;
648: xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = close;
649: return(xmlOutputCallbackNr++);
650: }
651:
652: /**
1.23 daniel 653: * xmlRegisterDefaultInputCallbacks:
654: *
655: * Registers the default compiled-in I/O handlers.
656: */
657: void
658: xmlRegisterDefaultInputCallbacks(void) {
1.34 veillard 659: if (xmlInputCallbackInitialized)
660: return;
661:
1.23 daniel 662: xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
663: xmlFileRead, xmlFileClose);
664: #ifdef HAVE_ZLIB_H
665: xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
666: xmlGzfileRead, xmlGzfileClose);
667: #endif /* HAVE_ZLIB_H */
668:
669: #ifdef LIBXML_HTTP_ENABLED
670: xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
671: xmlIOHTTPRead, xmlIOHTTPClose);
672: #endif /* LIBXML_HTTP_ENABLED */
673:
674: #ifdef LIBXML_FTP_ENABLED
675: xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
676: xmlIOFTPRead, xmlIOFTPClose);
677: #endif /* LIBXML_FTP_ENABLED */
1.34 veillard 678: xmlInputCallbackInitialized = 1;
1.23 daniel 679: }
1.22 daniel 680:
1.1 daniel 681: /**
1.27 daniel 682: * xmlRegisterDefaultOutputCallbacks:
683: *
684: * Registers the default compiled-in I/O handlers.
685: */
686: void
687: xmlRegisterDefaultOutputCallbacks(void) {
1.34 veillard 688: if (xmlOutputCallbackInitialized)
689: return;
690:
1.28 daniel 691: xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1.27 daniel 692: xmlFileWrite, xmlFileClose);
693: /*********************************
694: No way a-priori to distinguish between gzipped files from
695: uncompressed ones except opening if existing then closing
696: and saving with same compression ratio ... a pain.
697:
698: #ifdef HAVE_ZLIB_H
699: xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
700: xmlGzfileWrite, xmlGzfileClose);
701: #endif
702: No HTTP PUT support yet, patches welcome
703:
704: #ifdef LIBXML_HTTP_ENABLED
705: xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
706: xmlIOHTTPWrite, xmlIOHTTPClose);
707: #endif
708:
709: Nor FTP PUT ....
710: #ifdef LIBXML_FTP_ENABLED
711: xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
712: xmlIOFTPWrite, xmlIOFTPClose);
713: #endif
714: **********************************/
1.34 veillard 715: xmlOutputCallbackInitialized = 1;
1.27 daniel 716: }
717:
718: /**
1.1 daniel 719: * xmlAllocParserInputBuffer:
720: * @enc: the charset encoding if known
721: *
722: * Create a buffered parser input for progressive parsing
723: *
724: * Returns the new parser input or NULL
725: */
726: xmlParserInputBufferPtr
727: xmlAllocParserInputBuffer(xmlCharEncoding enc) {
728: xmlParserInputBufferPtr ret;
729:
1.8 daniel 730: ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1.1 daniel 731: if (ret == NULL) {
1.38 veillard 732: xmlGenericError(xmlGenericErrorContext,
733: "xmlAllocParserInputBuffer : out of memory!\n");
1.1 daniel 734: return(NULL);
735: }
1.3 veillard 736: memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1.1 daniel 737: ret->buffer = xmlBufferCreate();
1.17 daniel 738: if (ret->buffer == NULL) {
739: xmlFree(ret);
740: return(NULL);
741: }
742: ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1.1 daniel 743: ret->encoder = xmlGetCharEncodingHandler(enc);
1.26 daniel 744: if (ret->encoder != NULL)
745: ret->raw = xmlBufferCreate();
746: else
747: ret->raw = NULL;
1.23 daniel 748: ret->readcallback = NULL;
749: ret->closecallback = NULL;
750: ret->context = NULL;
1.1 daniel 751:
752: return(ret);
753: }
754:
755: /**
1.27 daniel 756: * xmlAllocOutputBuffer:
757: * @encoder: the encoding converter or NULL
758: *
759: * Create a buffered parser output
760: *
761: * Returns the new parser output or NULL
762: */
763: xmlOutputBufferPtr
764: xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
765: xmlOutputBufferPtr ret;
766:
767: ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
768: if (ret == NULL) {
1.38 veillard 769: xmlGenericError(xmlGenericErrorContext,
770: "xmlAllocOutputBuffer : out of memory!\n");
1.27 daniel 771: return(NULL);
772: }
773: memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
774: ret->buffer = xmlBufferCreate();
775: if (ret->buffer == NULL) {
776: xmlFree(ret);
777: return(NULL);
778: }
779: ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
780: ret->encoder = encoder;
1.28 daniel 781: if (encoder != NULL) {
782: ret->conv = xmlBufferCreateSize(4000);
783: /*
784: * This call is designed to initiate the encoder state
785: */
786: xmlCharEncOutFunc(encoder, ret->conv, NULL);
787: } else
788: ret->conv = NULL;
1.27 daniel 789: ret->writecallback = NULL;
790: ret->closecallback = NULL;
791: ret->context = NULL;
1.28 daniel 792: ret->written = 0;
1.27 daniel 793:
794: return(ret);
795: }
796:
797: /**
1.1 daniel 798: * xmlFreeParserInputBuffer:
799: * @in: a buffered parser input
800: *
801: * Free up the memory used by a buffered parser input
802: */
803: void
804: xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1.26 daniel 805: if (in->raw) {
806: xmlBufferFree(in->raw);
807: in->raw = NULL;
808: }
1.25 daniel 809: if (in->encoder != NULL) {
810: xmlCharEncCloseFunc(in->encoder);
811: }
812: if (in->closecallback != NULL) {
813: in->closecallback(in->context);
814: }
1.1 daniel 815: if (in->buffer != NULL) {
816: xmlBufferFree(in->buffer);
817: in->buffer = NULL;
818: }
1.23 daniel 819:
1.3 veillard 820: memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
1.8 daniel 821: xmlFree(in);
1.1 daniel 822: }
823:
824: /**
1.28 daniel 825: * xmlOutputBufferClose:
826: * @out: a buffered output
827: *
828: * flushes and close the output I/O channel
829: * and free up all the associated resources
830: *
831: * Returns the number of byte written or -1 in case of error.
832: */
833: int
834: xmlOutputBufferClose(xmlOutputBufferPtr out) {
835: int written;
836:
837: if (out == NULL)
838: return(-1);
1.39 ! veillard 839: if (out->writecallback != NULL)
! 840: xmlOutputBufferFlush(out);
1.28 daniel 841: if (out->closecallback != NULL) {
842: out->closecallback(out->context);
843: }
844: written = out->written;
845: if (out->conv) {
846: xmlBufferFree(out->conv);
847: out->conv = NULL;
848: }
849: if (out->encoder != NULL) {
850: xmlCharEncCloseFunc(out->encoder);
851: }
852: if (out->buffer != NULL) {
853: xmlBufferFree(out->buffer);
854: out->buffer = NULL;
855: }
856:
857: memset(out, 0xbe, (size_t) sizeof(xmlOutputBuffer));
858: xmlFree(out);
859: return(written);
860: }
861:
862: /**
1.1 daniel 863: * xmlParserInputBufferCreateFilename:
1.23 daniel 864: * @URI: a C string containing the URI or filename
1.1 daniel 865: * @enc: the charset encoding if known
866: *
867: * Create a buffered parser input for the progressive parsing of a file
868: * If filename is "-' then we use stdin as the input.
869: * Automatic support for ZLIB/Compress compressed document is provided
870: * by default if found at compile-time.
1.20 daniel 871: * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1.1 daniel 872: *
873: * Returns the new parser input or NULL
874: */
875: xmlParserInputBufferPtr
1.23 daniel 876: xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1.1 daniel 877: xmlParserInputBufferPtr ret;
1.23 daniel 878: int i;
879: void *context = NULL;
880:
881: if (xmlInputCallbackInitialized == 0)
882: xmlRegisterDefaultInputCallbacks();
1.1 daniel 883:
1.23 daniel 884: if (URI == NULL) return(NULL);
1.1 daniel 885:
1.23 daniel 886: /*
887: * Try to find one of the input accept method accepting taht scheme
888: * Go in reverse to give precedence to user defined handlers.
889: */
890: for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
891: if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
892: (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
893: context = xmlInputCallbackTable[i].opencallback(URI);
894: if (context != NULL)
895: break;
1.1 daniel 896: }
1.23 daniel 897: }
898: if (context == NULL) {
899: return(NULL);
1.1 daniel 900: }
1.20 daniel 901:
902: /*
903: * Allocate the Input buffer front-end.
1.1 daniel 904: */
905: ret = xmlAllocParserInputBuffer(enc);
906: if (ret != NULL) {
1.23 daniel 907: ret->context = context;
908: ret->readcallback = xmlInputCallbackTable[i].readcallback;
909: ret->closecallback = xmlInputCallbackTable[i].closecallback;
1.1 daniel 910: }
911: return(ret);
912: }
913:
914: /**
1.27 daniel 915: * xmlOutputBufferCreateFilename:
916: * @URI: a C string containing the URI or filename
917: * @encoder: the encoding converter or NULL
1.28 daniel 918: * @compression: the compression ration (0 none, 9 max).
1.27 daniel 919: *
920: * Create a buffered output for the progressive saving of a file
921: * If filename is "-' then we use stdout as the output.
922: * Automatic support for ZLIB/Compress compressed document is provided
923: * by default if found at compile-time.
1.28 daniel 924: * TODO: currently if compression is set, the library only support
925: * writing to a local file.
1.27 daniel 926: *
927: * Returns the new output or NULL
928: */
929: xmlOutputBufferPtr
930: xmlOutputBufferCreateFilename(const char *URI,
1.28 daniel 931: xmlCharEncodingHandlerPtr encoder,
932: int compression) {
1.27 daniel 933: xmlOutputBufferPtr ret;
934: int i;
935: void *context = NULL;
936:
937: if (xmlOutputCallbackInitialized == 0)
938: xmlRegisterDefaultOutputCallbacks();
939:
940: if (URI == NULL) return(NULL);
941:
1.28 daniel 942: #ifdef HAVE_ZLIB_H
943: if ((compression > 0) && (compression <= 9)) {
944: context = xmlGzfileOpenW(URI, compression);
945: if (context != NULL) {
946: ret = xmlAllocOutputBuffer(encoder);
947: if (ret != NULL) {
948: ret->context = context;
949: ret->writecallback = xmlGzfileWrite;
950: ret->closecallback = xmlGzfileClose;
951: }
952: return(ret);
953: }
954: }
955: #endif
956:
1.27 daniel 957: /*
958: * Try to find one of the output accept method accepting taht scheme
959: * Go in reverse to give precedence to user defined handlers.
960: */
961: for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
962: if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
963: (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
964: context = xmlOutputCallbackTable[i].opencallback(URI);
965: if (context != NULL)
966: break;
967: }
968: }
969: if (context == NULL) {
970: return(NULL);
971: }
972:
973: /*
974: * Allocate the Output buffer front-end.
975: */
976: ret = xmlAllocOutputBuffer(encoder);
977: if (ret != NULL) {
978: ret->context = context;
979: ret->writecallback = xmlOutputCallbackTable[i].writecallback;
980: ret->closecallback = xmlOutputCallbackTable[i].closecallback;
981: }
982: return(ret);
983: }
984:
985: /**
1.1 daniel 986: * xmlParserInputBufferCreateFile:
987: * @file: a FILE*
988: * @enc: the charset encoding if known
989: *
990: * Create a buffered parser input for the progressive parsing of a FILE *
991: * buffered C I/O
992: *
993: * Returns the new parser input or NULL
994: */
995: xmlParserInputBufferPtr
996: xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
997: xmlParserInputBufferPtr ret;
998:
1.23 daniel 999: if (xmlInputCallbackInitialized == 0)
1000: xmlRegisterDefaultInputCallbacks();
1001:
1.1 daniel 1002: if (file == NULL) return(NULL);
1003:
1004: ret = xmlAllocParserInputBuffer(enc);
1.23 daniel 1005: if (ret != NULL) {
1006: ret->context = file;
1007: ret->readcallback = xmlFileRead;
1.37 veillard 1008: ret->closecallback = xmlFileFlush;
1.23 daniel 1009: }
1.1 daniel 1010:
1011: return(ret);
1012: }
1013:
1014: /**
1.27 daniel 1015: * xmlOutputBufferCreateFile:
1016: * @file: a FILE*
1017: * @encoder: the encoding converter or NULL
1018: *
1019: * Create a buffered output for the progressive saving to a FILE *
1020: * buffered C I/O
1021: *
1022: * Returns the new parser output or NULL
1023: */
1024: xmlOutputBufferPtr
1025: xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1026: xmlOutputBufferPtr ret;
1027:
1028: if (xmlOutputCallbackInitialized == 0)
1029: xmlRegisterDefaultOutputCallbacks();
1030:
1031: if (file == NULL) return(NULL);
1032:
1033: ret = xmlAllocOutputBuffer(encoder);
1034: if (ret != NULL) {
1035: ret->context = file;
1036: ret->writecallback = xmlFileWrite;
1.37 veillard 1037: ret->closecallback = xmlFileFlush;
1.27 daniel 1038: }
1039:
1040: return(ret);
1041: }
1042:
1043: /**
1.1 daniel 1044: * xmlParserInputBufferCreateFd:
1045: * @fd: a file descriptor number
1046: * @enc: the charset encoding if known
1047: *
1048: * Create a buffered parser input for the progressive parsing for the input
1049: * from a file descriptor
1050: *
1051: * Returns the new parser input or NULL
1052: */
1053: xmlParserInputBufferPtr
1054: xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1055: xmlParserInputBufferPtr ret;
1056:
1057: if (fd < 0) return(NULL);
1058:
1059: ret = xmlAllocParserInputBuffer(enc);
1.23 daniel 1060: if (ret != NULL) {
1061: ret->context = (void *) fd;
1062: ret->readcallback = xmlFdRead;
1063: ret->closecallback = xmlFdClose;
1064: }
1.1 daniel 1065:
1066: return(ret);
1067: }
1068:
1069: /**
1.31 veillard 1070: * xmlParserInputBufferCreateMem:
1071: * @mem: the memory input
1072: * @size: the length of the memory block
1073: * @enc: the charset encoding if known
1074: *
1075: * Create a buffered parser input for the progressive parsing for the input
1076: * from a file descriptor
1077: *
1078: * Returns the new parser input or NULL
1079: */
1080: xmlParserInputBufferPtr
1081: xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1082: xmlParserInputBufferPtr ret;
1083:
1084: if (size <= 0) return(NULL);
1085: if (mem == NULL) return(NULL);
1086:
1087: ret = xmlAllocParserInputBuffer(enc);
1088: if (ret != NULL) {
1089: ret->context = (void *) mem;
1.32 veillard 1090: ret->readcallback = (xmlInputReadCallback) xmlNop;
1.31 veillard 1091: ret->closecallback = NULL;
1092: xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1093: }
1094:
1095: return(ret);
1096: }
1097:
1098: /**
1.27 daniel 1099: * xmlOutputBufferCreateFd:
1100: * @fd: a file descriptor number
1101: * @encoder: the encoding converter or NULL
1102: *
1103: * Create a buffered output for the progressive saving
1104: * to a file descriptor
1105: *
1106: * Returns the new parser output or NULL
1107: */
1108: xmlOutputBufferPtr
1109: xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1110: xmlOutputBufferPtr ret;
1111:
1112: if (fd < 0) return(NULL);
1113:
1114: ret = xmlAllocOutputBuffer(encoder);
1115: if (ret != NULL) {
1116: ret->context = (void *) fd;
1117: ret->writecallback = xmlFdWrite;
1118: ret->closecallback = xmlFdClose;
1119: }
1120:
1121: return(ret);
1122: }
1123:
1124: /**
1.24 daniel 1125: * xmlParserInputBufferCreateIO:
1126: * @ioread: an I/O read function
1127: * @ioclose: an I/O close function
1128: * @ioctx: an I/O handler
1129: * @enc: the charset encoding if known
1130: *
1131: * Create a buffered parser input for the progressive parsing for the input
1.27 daniel 1132: * from an I/O handler
1.24 daniel 1133: *
1134: * Returns the new parser input or NULL
1135: */
1136: xmlParserInputBufferPtr
1137: xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1138: xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1139: xmlParserInputBufferPtr ret;
1140:
1141: if (ioread == NULL) return(NULL);
1142:
1143: ret = xmlAllocParserInputBuffer(enc);
1144: if (ret != NULL) {
1145: ret->context = (void *) ioctx;
1146: ret->readcallback = ioread;
1147: ret->closecallback = ioclose;
1148: }
1149:
1150: return(ret);
1151: }
1152:
1153: /**
1.27 daniel 1154: * xmlOutputBufferCreateIO:
1155: * @iowrite: an I/O write function
1156: * @ioclose: an I/O close function
1157: * @ioctx: an I/O handler
1158: * @enc: the charset encoding if known
1159: *
1160: * Create a buffered output for the progressive saving
1161: * to an I/O handler
1162: *
1163: * Returns the new parser output or NULL
1164: */
1165: xmlOutputBufferPtr
1166: xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1167: xmlOutputCloseCallback ioclose, void *ioctx,
1168: xmlCharEncodingHandlerPtr encoder) {
1169: xmlOutputBufferPtr ret;
1170:
1171: if (iowrite == NULL) return(NULL);
1172:
1173: ret = xmlAllocOutputBuffer(encoder);
1174: if (ret != NULL) {
1175: ret->context = (void *) ioctx;
1176: ret->writecallback = iowrite;
1177: ret->closecallback = ioclose;
1178: }
1179:
1180: return(ret);
1181: }
1182:
1183: /**
1.14 daniel 1184: * xmlParserInputBufferPush:
1185: * @in: a buffered parser input
1.27 daniel 1186: * @len: the size in bytes of the array.
1.14 daniel 1187: * @buf: an char array
1188: *
1189: * Push the content of the arry in the input buffer
1190: * This routine handle the I18N transcoding to internal UTF-8
1191: * This is used when operating the parser in progressive (push) mode.
1192: *
1193: * Returns the number of chars read and stored in the buffer, or -1
1194: * in case of error.
1195: */
1196: int
1.38 veillard 1197: xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1198: int len, const char *buf) {
1.14 daniel 1199: int nbchars = 0;
1200:
1201: if (len < 0) return(0);
1202: if (in->encoder != NULL) {
1.26 daniel 1203: /*
1204: * Store the data in the incoming raw buffer
1205: */
1206: if (in->raw == NULL) {
1207: in->raw = xmlBufferCreate();
1208: }
1209: xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1.14 daniel 1210:
1211: /*
1.26 daniel 1212: * convert as much as possible to the parser reading buffer.
1.14 daniel 1213: */
1.26 daniel 1214: nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1.20 daniel 1215: if (nbchars < 0) {
1.38 veillard 1216: xmlGenericError(xmlGenericErrorContext,
1217: "xmlParserInputBufferPush: encoder error\n");
1.20 daniel 1218: return(-1);
1219: }
1.14 daniel 1220: } else {
1221: nbchars = len;
1.17 daniel 1222: xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1.14 daniel 1223: }
1224: #ifdef DEBUG_INPUT
1.38 veillard 1225: xmlGenericError(xmlGenericErrorContext,
1226: "I/O: pushed %d chars, buffer %d/%d\n",
1.14 daniel 1227: nbchars, in->buffer->use, in->buffer->size);
1228: #endif
1229: return(nbchars);
1230: }
1231:
1232: /**
1.1 daniel 1233: * xmlParserInputBufferGrow:
1234: * @in: a buffered parser input
1235: * @len: indicative value of the amount of chars to read
1236: *
1237: * Grow up the content of the input buffer, the old data are preserved
1238: * This routine handle the I18N transcoding to internal UTF-8
1.14 daniel 1239: * This routine is used when operating the parser in normal (pull) mode
1.26 daniel 1240: *
1241: * TODO: one should be able to remove one extra copy by copying directy
1242: * onto in->buffer or in->raw
1.1 daniel 1243: *
1244: * Returns the number of chars read and stored in the buffer, or -1
1245: * in case of error.
1246: */
1247: int
1248: xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1249: char *buffer = NULL;
1250: int res = 0;
1251: int nbchars = 0;
1252: int buffree;
1253:
1254: if ((len <= MINLEN) && (len != 4))
1255: len = MINLEN;
1256: buffree = in->buffer->size - in->buffer->use;
1257: if (buffree <= 0) {
1.38 veillard 1258: xmlGenericError(xmlGenericErrorContext,
1259: "xmlParserInputBufferGrow : buffer full !\n");
1.1 daniel 1260: return(0);
1261: }
1262: if (len > buffree)
1263: len = buffree;
1264:
1.30 veillard 1265: buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
1.1 daniel 1266: if (buffer == NULL) {
1.38 veillard 1267: xmlGenericError(xmlGenericErrorContext,
1268: "xmlParserInputBufferGrow : out of memory !\n");
1.1 daniel 1269: return(-1);
1270: }
1.23 daniel 1271:
1272: /*
1273: * Call the read method for this I/O type.
1274: */
1275: if (in->readcallback != NULL) {
1276: res = in->readcallback(in->context, &buffer[0], len);
1.1 daniel 1277: } else {
1.38 veillard 1278: xmlGenericError(xmlGenericErrorContext,
1279: "xmlParserInputBufferGrow : no input !\n");
1.8 daniel 1280: xmlFree(buffer);
1.1 daniel 1281: return(-1);
1282: }
1283: if (res < 0) {
1284: perror ("read error");
1.8 daniel 1285: xmlFree(buffer);
1.1 daniel 1286: return(-1);
1287: }
1.29 daniel 1288: len = res;
1.1 daniel 1289: if (in->encoder != NULL) {
1.26 daniel 1290: /*
1291: * Store the data in the incoming raw buffer
1292: */
1293: if (in->raw == NULL) {
1294: in->raw = xmlBufferCreate();
1.1 daniel 1295: }
1.26 daniel 1296: xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
1.20 daniel 1297:
1298: /*
1.26 daniel 1299: * convert as much as possible to the parser reading buffer.
1.20 daniel 1300: */
1.26 daniel 1301: nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1302: if (nbchars < 0) {
1.38 veillard 1303: xmlGenericError(xmlGenericErrorContext,
1304: "xmlParserInputBufferGrow: encoder error\n");
1.26 daniel 1305: return(-1);
1.20 daniel 1306: }
1.1 daniel 1307: } else {
1.29 daniel 1308: nbchars = len;
1.3 veillard 1309: buffer[nbchars] = 0;
1.13 daniel 1310: xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
1.1 daniel 1311: }
1312: #ifdef DEBUG_INPUT
1.38 veillard 1313: xmlGenericError(xmlGenericErrorContext,
1314: "I/O: read %d chars, buffer %d/%d\n",
1.1 daniel 1315: nbchars, in->buffer->use, in->buffer->size);
1316: #endif
1.8 daniel 1317: xmlFree(buffer);
1.1 daniel 1318: return(nbchars);
1319: }
1320:
1321: /**
1322: * xmlParserInputBufferRead:
1323: * @in: a buffered parser input
1324: * @len: indicative value of the amount of chars to read
1325: *
1326: * Refresh the content of the input buffer, the old data are considered
1327: * consumed
1328: * This routine handle the I18N transcoding to internal UTF-8
1329: *
1330: * Returns the number of chars read and stored in the buffer, or -1
1331: * in case of error.
1332: */
1333: int
1334: xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1335: /* xmlBufferEmpty(in->buffer); */
1.23 daniel 1336: if (in->readcallback != NULL)
1.17 daniel 1337: return(xmlParserInputBufferGrow(in, len));
1338: else
1.27 daniel 1339: return(-1);
1340: }
1341:
1342: /**
1343: * xmlOutputBufferWrite:
1344: * @out: a buffered parser output
1345: * @len: the size in bytes of the array.
1346: * @buf: an char array
1347: *
1348: * Write the content of the array in the output I/O buffer
1349: * This routine handle the I18N transcoding from internal UTF-8
1350: * The buffer is lossless, i.e. will store in case of partial
1351: * or delayed writes.
1352: *
1353: * Returns the number of chars immediately written, or -1
1354: * in case of error.
1355: */
1356: int
1357: xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
1358: int nbchars = 0, ret;
1359:
1360: if (len < 0) return(0);
1361:
1362: /*
1363: * first handle encoding stuff.
1364: */
1365: if (out->encoder != NULL) {
1366: /*
1367: * Store the data in the incoming raw buffer
1368: */
1.28 daniel 1369: if (out->conv == NULL) {
1370: out->conv = xmlBufferCreate();
1.27 daniel 1371: }
1.28 daniel 1372: xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1.27 daniel 1373:
1.28 daniel 1374: if (out->buffer->use < MINLEN)
1.27 daniel 1375: return(0);
1376:
1377: /*
1378: * convert as much as possible to the parser reading buffer.
1379: */
1.28 daniel 1380: nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1.27 daniel 1381: if (nbchars < 0) {
1.38 veillard 1382: xmlGenericError(xmlGenericErrorContext,
1383: "xmlOutputBufferWrite: encoder error\n");
1.27 daniel 1384: return(-1);
1385: }
1.28 daniel 1386: nbchars = out->conv->use;
1.27 daniel 1387: } else {
1388: xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
1.28 daniel 1389: nbchars = out->buffer->use;
1.27 daniel 1390: }
1391: if (nbchars < MINLEN)
1392: return(0);
1393:
1394: /*
1395: * second write the stuff to the I/O channel
1396: */
1.28 daniel 1397: if (out->encoder != NULL) {
1398: ret = out->writecallback(out->context,
1399: (const char *)out->conv->content, nbchars);
1400: if (ret >= 0)
1401: xmlBufferShrink(out->conv, nbchars);
1402: } else {
1403: ret = out->writecallback(out->context,
1.27 daniel 1404: (const char *)out->buffer->content, nbchars);
1.28 daniel 1405: if (ret >= 0)
1406: xmlBufferShrink(out->buffer, nbchars);
1407: }
1.27 daniel 1408: if (ret < 0) {
1.38 veillard 1409: xmlGenericError(xmlGenericErrorContext,
1410: "I/O: error %d writing %d bytes\n", ret, nbchars);
1.27 daniel 1411: return(ret);
1412: }
1.28 daniel 1413: out->written += ret;
1.27 daniel 1414:
1415: #ifdef DEBUG_INPUT
1.38 veillard 1416: xmlGenericError(xmlGenericErrorContext,
1417: "I/O: wrote %d chars\n", ret);
1.27 daniel 1418: #endif
1419: return(nbchars);
1.28 daniel 1420: }
1421:
1422: /**
1423: * xmlOutputBufferWriteString:
1424: * @out: a buffered parser output
1425: * @str: a zero terminated C string
1426: *
1427: * Write the content of the string in the output I/O buffer
1428: * This routine handle the I18N transcoding from internal UTF-8
1429: * The buffer is lossless, i.e. will store in case of partial
1430: * or delayed writes.
1431: *
1432: * Returns the number of chars immediately written, or -1
1433: * in case of error.
1434: */
1435: int
1436: xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
1437: int len;
1438:
1439: if (str == NULL)
1440: return(-1);
1441: len = strlen(str);
1442:
1443: if (len > 0)
1444: return(xmlOutputBufferWrite(out, len, str));
1445: return(len);
1446: }
1447:
1448: /**
1449: * xmlOutputBufferFlush:
1450: * @out: a buffered output
1451: *
1452: * flushes the output I/O channel
1453: *
1454: * Returns the number of byte written or -1 in case of error.
1455: */
1456: int
1457: xmlOutputBufferFlush(xmlOutputBufferPtr out) {
1458: int nbchars = 0, ret;
1459:
1460: /*
1461: * first handle encoding stuff.
1462: */
1463: if ((out->conv != NULL) && (out->encoder != NULL)) {
1464: /*
1465: * convert as much as possible to the parser reading buffer.
1466: */
1467: nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
1468: if (nbchars < 0) {
1.38 veillard 1469: xmlGenericError(xmlGenericErrorContext,
1470: "xmlOutputBufferWrite: encoder error\n");
1.28 daniel 1471: return(-1);
1472: }
1473: }
1474:
1475: /*
1476: * second flush the stuff to the I/O channel
1477: */
1478: if ((out->conv != NULL) && (out->encoder != NULL)) {
1479: ret = out->writecallback(out->context,
1480: (const char *)out->conv->content, out->conv->use);
1481: if (ret >= 0)
1482: xmlBufferShrink(out->conv, ret);
1483: } else {
1484: ret = out->writecallback(out->context,
1485: (const char *)out->buffer->content, out->buffer->use);
1486: if (ret >= 0)
1487: xmlBufferShrink(out->buffer, ret);
1488: }
1489: if (ret < 0) {
1.38 veillard 1490: xmlGenericError(xmlGenericErrorContext,
1491: "I/O: error %d flushing %d bytes\n", ret, nbchars);
1.28 daniel 1492: return(ret);
1493: }
1494: out->written += ret;
1495:
1496: #ifdef DEBUG_INPUT
1.38 veillard 1497: xmlGenericError(xmlGenericErrorContext,
1498: "I/O: flushed %d chars\n", ret);
1.28 daniel 1499: #endif
1500: return(ret);
1.4 daniel 1501: }
1502:
1503: /*
1504: * xmlParserGetDirectory:
1505: * @filename: the path to a file
1506: *
1507: * lookup the directory for that file
1508: *
1509: * Returns a new allocated string containing the directory, or NULL.
1510: */
1511: char *
1512: xmlParserGetDirectory(const char *filename) {
1513: char *ret = NULL;
1514: char dir[1024];
1515: char *cur;
1516: char sep = '/';
1.23 daniel 1517:
1518: if (xmlInputCallbackInitialized == 0)
1519: xmlRegisterDefaultInputCallbacks();
1.4 daniel 1520:
1521: if (filename == NULL) return(NULL);
1522: #ifdef WIN32
1523: sep = '\\';
1524: #endif
1525:
1526: strncpy(dir, filename, 1023);
1527: dir[1023] = 0;
1528: cur = &dir[strlen(dir)];
1529: while (cur > dir) {
1530: if (*cur == sep) break;
1531: cur --;
1532: }
1533: if (*cur == sep) {
1534: if (cur == dir) dir[1] = 0;
1535: else *cur = 0;
1.8 daniel 1536: ret = xmlMemStrdup(dir);
1.4 daniel 1537: } else {
1538: if (getcwd(dir, 1024) != NULL) {
1539: dir[1023] = 0;
1.8 daniel 1540: ret = xmlMemStrdup(dir);
1.4 daniel 1541: }
1542: }
1543: return(ret);
1.5 daniel 1544: }
1545:
1546: /****************************************************************
1547: * *
1548: * External entities loading *
1549: * *
1550: ****************************************************************/
1551:
1552: /*
1553: * xmlDefaultExternalEntityLoader:
1554: * @URL: the URL for the entity to load
1555: * @ID: the System ID for the entity to load
1.18 daniel 1556: * @ctxt: the context in which the entity is called or NULL
1.5 daniel 1557: *
1558: * By default we don't load external entitites, yet.
1559: *
1560: * Returns a new allocated xmlParserInputPtr, or NULL.
1561: */
1562: static
1563: xmlParserInputPtr
1564: xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
1.18 daniel 1565: xmlParserCtxtPtr ctxt) {
1566: xmlParserInputPtr ret = NULL;
1.33 veillard 1567:
1.5 daniel 1568: #ifdef DEBUG_EXTERNAL_ENTITIES
1.38 veillard 1569: xmlGenericError(xmlGenericErrorContext,
1570: "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
1.5 daniel 1571: #endif
1.18 daniel 1572: if (URL == NULL) {
1573: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1.38 veillard 1574: ctxt->sax->warning(ctxt,
1575: "failed to load external entity \"%s\"\n", ID);
1.18 daniel 1576: return(NULL);
1577: }
1578: ret = xmlNewInputFromFile(ctxt, URL);
1579: if (ret == NULL) {
1580: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1.38 veillard 1581: ctxt->sax->warning(ctxt,
1582: "failed to load external entity \"%s\"\n", URL);
1.18 daniel 1583: }
1584: return(ret);
1.5 daniel 1585: }
1586:
1587: static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1588: xmlDefaultExternalEntityLoader;
1589:
1590: /*
1591: * xmlSetExternalEntityLoader:
1592: * @f: the new entity resolver function
1593: *
1594: * Changes the defaultexternal entity resolver function for the application
1595: */
1596: void
1597: xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1598: xmlCurrentExternalEntityLoader = f;
1599: }
1600:
1601: /*
1602: * xmlGetExternalEntityLoader:
1603: *
1604: * Get the default external entity resolver function for the application
1605: *
1606: * Returns the xmlExternalEntityLoader function pointer
1607: */
1608: xmlExternalEntityLoader
1609: xmlGetExternalEntityLoader(void) {
1610: return(xmlCurrentExternalEntityLoader);
1611: }
1612:
1613: /*
1614: * xmlLoadExternalEntity:
1615: * @URL: the URL for the entity to load
1616: * @ID: the System ID for the entity to load
1.18 daniel 1617: * @ctxt: the context in which the entity is called or NULL
1.5 daniel 1618: *
1619: * Load an external entity, note that the use of this function for
1620: * unparsed entities may generate problems
1.6 daniel 1621: * TODO: a more generic External entitiy API must be designed
1.5 daniel 1622: *
1623: * Returns the xmlParserInputPtr or NULL
1624: */
1625: xmlParserInputPtr
1626: xmlLoadExternalEntity(const char *URL, const char *ID,
1.18 daniel 1627: xmlParserCtxtPtr ctxt) {
1628: return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
1.1 daniel 1629: }
1630:
Webmaster