Annotation of XML/xmlIO.c, revision 1.27
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.1 daniel 43:
44: /* #define DEBUG_INPUT */
1.2 daniel 45: /* #define VERBOSE_FAILURE */
1.5 daniel 46: /* #define DEBUG_EXTERNAL_ENTITIES */
1.1 daniel 47:
48: #ifdef DEBUG_INPUT
49: #define MINLEN 40
50: #else
51: #define MINLEN 4000
52: #endif
53:
1.22 daniel 54: /*
55: * Input I/O callback sets
56: */
57: typedef struct _xmlInputCallback {
58: xmlInputMatchCallback matchcallback;
59: xmlInputOpenCallback opencallback;
60: xmlInputReadCallback readcallback;
61: xmlInputCloseCallback closecallback;
62: } xmlInputCallback;
63:
1.23 daniel 64: #define MAX_INPUT_CALLBACK 15
1.22 daniel 65:
1.23 daniel 66: xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
67: int xmlInputCallbackNr = 0;
68: int xmlInputCallbackInitialized = 0;
69:
1.27 ! daniel 70: /*
! 71: * Output I/O callback sets
! 72: */
! 73: typedef struct _xmlOutputCallback {
! 74: xmlOutputMatchCallback matchcallback;
! 75: xmlOutputOpenCallback opencallback;
! 76: xmlOutputWriteCallback writecallback;
! 77: xmlOutputCloseCallback closecallback;
! 78: } xmlOutputCallback;
! 79:
! 80: #define MAX_OUTPUT_CALLBACK 15
! 81:
! 82: xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
! 83: int xmlOutputCallbackNr = 0;
! 84: int xmlOutputCallbackInitialized = 0;
! 85:
1.23 daniel 86: /************************************************************************
87: * *
88: * Standard I/O for file accesses *
89: * *
90: ************************************************************************/
1.22 daniel 91:
92: /**
1.23 daniel 93: * xmlFdMatch:
1.22 daniel 94: * @filename: the URI for matching
95: *
96: * input from file descriptor
97: *
98: * Returns 1 if matches, 0 otherwise
99: */
1.23 daniel 100: int
101: xmlFdMatch (const char *filename) {
102: return(1);
103: }
104:
105: /**
106: * xmlFdOpen:
107: * @filename: the URI for matching
108: *
109: * input from file descriptor, supports compressed input
110: * if @filename is " " then the standard input is used
111: *
112: * Returns an I/O context or NULL in case of error
113: */
114: void *
115: xmlFdOpen (const char *filename) {
116: const char *path = NULL;
117: int fd;
118:
119: if (!strcmp(filename, "-")) {
120: fd = 0;
121: return((void *) fd);
122: }
123:
1.22 daniel 124: if (!strncmp(filename, "file://localhost", 16))
1.23 daniel 125: path = &filename[16];
126: else if (!strncmp(filename, "file:///", 8))
127: path = &filename[8];
128: else if (filename[0] == '/')
129: path = filename;
130: if (path == NULL)
131: return(NULL);
132:
133: #ifdef WIN32
134: fd = _open (filename, O_RDONLY | _O_BINARY);
135: #else
136: fd = open (filename, O_RDONLY);
137: #endif
138:
139: return((void *) fd);
140: }
141:
142: /**
143: * xmlFdRead:
144: * @context: the I/O context
145: * @buffer: where to drop data
1.27 ! daniel 146: * @len: number of bytes to read
1.23 daniel 147: *
148: * Read @len bytes to @buffer from the I/O channel.
149: *
150: * Returns the number of bytes written
151: */
152: int
153: xmlFdRead (void * context, char * buffer, int len) {
154: return(read((int) context, &buffer[0], len));
155: }
156:
157: /**
1.27 ! daniel 158: * xmlFdWrite:
! 159: * @context: the I/O context
! 160: * @buffer: where to get data
! 161: * @len: number of bytes to write
! 162: *
! 163: * Write @len bytes from @buffer to the I/O channel.
! 164: *
! 165: * Returns the number of bytes written
! 166: */
! 167: int
! 168: xmlFdWrite (void * context, const char * buffer, int len) {
! 169: return(write((int) context, &buffer[0], len));
! 170: }
! 171:
! 172: /**
1.23 daniel 173: * xmlFdClose:
174: * @context: the I/O context
175: *
176: * Close an I/O channel
177: */
178: void
179: xmlFdClose (void * context) {
180: close((int) context);
1.22 daniel 181: }
1.23 daniel 182:
1.22 daniel 183: /**
1.23 daniel 184: * xmlFileMatch:
1.22 daniel 185: * @filename: the URI for matching
186: *
1.23 daniel 187: * input from FILE *
1.22 daniel 188: *
189: * Returns 1 if matches, 0 otherwise
190: */
1.23 daniel 191: int
192: xmlFileMatch (const char *filename) {
193: return(1);
194: }
195:
196: /**
197: * xmlFileOpen:
198: * @filename: the URI for matching
199: *
200: * input from FILE *, supports compressed input
201: * if @filename is " " then the standard input is used
202: *
203: * Returns an I/O context or NULL in case of error
204: */
205: void *
206: xmlFileOpen (const char *filename) {
1.22 daniel 207: const char *path = NULL;
1.23 daniel 208: FILE *fd;
209:
210: if (!strcmp(filename, "-")) {
211: fd = stdin;
212: return((void *) fd);
213: }
1.22 daniel 214:
215: if (!strncmp(filename, "file://localhost", 16))
216: path = &filename[16];
217: else if (!strncmp(filename, "file:///", 8))
1.23 daniel 218: path = &filename[8];
219: else
1.22 daniel 220: path = filename;
221: if (path == NULL)
1.23 daniel 222: return(NULL);
223:
1.22 daniel 224: #ifdef WIN32
1.23 daniel 225: fd = fopen(path, "rb");
1.22 daniel 226: #else
1.23 daniel 227: fd = fopen(path, "r");
228: #endif /* WIN32 */
229: return((void *) fd);
230: }
231:
232: /**
233: * xmlFileRead:
234: * @context: the I/O context
235: * @buffer: where to drop data
236: * @len: number of bytes to write
237: *
238: * Read @len bytes to @buffer from the I/O channel.
239: *
240: * Returns the number of bytes written
241: */
242: int
243: xmlFileRead (void * context, char * buffer, int len) {
244: return(fread(&buffer[0], 1, len, (FILE *) context));
245: }
246:
247: /**
1.27 ! daniel 248: * xmlFileWrite:
! 249: * @context: the I/O context
! 250: * @buffer: where to drop data
! 251: * @len: number of bytes to write
! 252: *
! 253: * Write @len bytes from @buffer to the I/O channel.
! 254: *
! 255: * Returns the number of bytes written
! 256: */
! 257: int
! 258: xmlFileWrite (void * context, const char * buffer, int len) {
! 259: return(fwrite(&buffer[0], 1, len, (FILE *) context));
! 260: }
! 261:
! 262: /**
1.23 daniel 263: * xmlFileClose:
264: * @context: the I/O context
265: *
266: * Close an I/O channel
267: */
268: void
269: xmlFileClose (void * context) {
270: fclose((FILE *) context);
271: }
272:
273: #ifdef HAVE_ZLIB_H
274: /************************************************************************
275: * *
276: * I/O for compressed file accesses *
277: * *
278: ************************************************************************/
279: /**
280: * xmlGzfileMatch:
281: * @filename: the URI for matching
282: *
283: * input from compressed file test
284: *
285: * Returns 1 if matches, 0 otherwise
286: */
287: int
288: xmlGzfileMatch (const char *filename) {
289: return(1);
290: }
291:
292: /**
293: * xmlGzfileOpen:
294: * @filename: the URI for matching
295: *
296: * input from compressed file open
297: * if @filename is " " then the standard input is used
298: *
299: * Returns an I/O context or NULL in case of error
300: */
301: void *
302: xmlGzfileOpen (const char *filename) {
303: const char *path = NULL;
304: gzFile fd;
305:
306: if (!strcmp(filename, "-")) {
307: fd = gzdopen (fileno(stdin), "r");
308: return((void *) fd);
309: }
310:
311: if (!strncmp(filename, "file://localhost", 16))
312: path = &filename[16];
313: else if (!strncmp(filename, "file:///", 8))
314: path = &filename[8];
315: else
316: path = filename;
317:
318: fd = gzopen(filename, "r");
319: return((void *) fd);
320: }
321:
322: /**
323: * xmlGzfileRead:
324: * @context: the I/O context
325: * @buffer: where to drop data
326: * @len: number of bytes to write
327: *
328: * Read @len bytes to @buffer from the compressed I/O channel.
329: *
330: * Returns the number of bytes written
331: */
332: int
333: xmlGzfileRead (void * context, char * buffer, int len) {
334: return(gzread((gzFile) context, &buffer[0], len));
335: }
336:
337: /**
338: * xmlGzfileClose:
339: * @context: the I/O context
340: *
341: * Close a compressed I/O channel
342: */
343: void
344: xmlGzfileClose (void * context) {
345: gzclose((gzFile) context);
346: }
347: #endif /* HAVE_ZLIB_H */
348:
349: #ifdef LIBXML_HTTP_ENABLED
350: /************************************************************************
351: * *
352: * I/O for HTTP file accesses *
353: * *
354: ************************************************************************/
355: /**
356: * xmlIOHTTPMatch:
357: * @filename: the URI for matching
358: *
359: * check if the URI matches an HTTP one
360: *
361: * Returns 1 if matches, 0 otherwise
362: */
363: int
364: xmlIOHTTPMatch (const char *filename) {
365: if (!strncmp(filename, "http://", 7))
366: return(1);
367: return(0);
368: }
369:
370: /**
371: * xmlIOHTTPOpen:
372: * @filename: the URI for matching
373: *
374: * open an HTTP I/O channel
375: *
376: * Returns an I/O context or NULL in case of error
377: */
378: void *
379: xmlIOHTTPOpen (const char *filename) {
380: return(xmlNanoHTTPOpen(filename, NULL));
381: }
382:
383: /**
384: * xmlIOHTTPRead:
385: * @context: the I/O context
386: * @buffer: where to drop data
387: * @len: number of bytes to write
388: *
389: * Read @len bytes to @buffer from the I/O channel.
390: *
391: * Returns the number of bytes written
392: */
393: int
394: xmlIOHTTPRead(void * context, char * buffer, int len) {
395: return(xmlNanoHTTPRead(context, &buffer[0], len));
1.22 daniel 396: }
397:
1.23 daniel 398: /**
399: * xmlIOHTTPClose:
400: * @context: the I/O context
401: *
402: * Close an HTTP I/O channel
403: */
404: void
405: xmlIOHTTPClose (void * context) {
406: xmlNanoHTTPClose(context);
1.22 daniel 407: }
1.23 daniel 408: #endif /* LIBXML_HTTP_ENABLED */
409:
410: #ifdef LIBXML_FTP_ENABLED
411: /************************************************************************
412: * *
413: * I/O for FTP file accesses *
414: * *
415: ************************************************************************/
416: /**
417: * xmlIOFTPMatch:
418: * @filename: the URI for matching
419: *
420: * check if the URI matches an FTP one
421: *
422: * Returns 1 if matches, 0 otherwise
423: */
424: int
425: xmlIOFTPMatch (const char *filename) {
426: if (!strncmp(filename, "ftp://", 6))
427: return(1);
428: return(0);
1.22 daniel 429: }
430:
1.23 daniel 431: /**
432: * xmlIOFTPOpen:
433: * @filename: the URI for matching
434: *
435: * open an FTP I/O channel
436: *
437: * Returns an I/O context or NULL in case of error
438: */
439: void *
440: xmlIOFTPOpen (const char *filename) {
441: return(xmlNanoFTPOpen(filename));
1.22 daniel 442: }
1.23 daniel 443:
444: /**
445: * xmlIOFTPRead:
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 I/O channel.
451: *
452: * Returns the number of bytes written
453: */
454: int
455: xmlIOFTPRead(void * context, char * buffer, int len) {
456: return(xmlNanoFTPRead(context, &buffer[0], len));
1.22 daniel 457: }
1.23 daniel 458:
459: /**
460: * xmlIOFTPClose:
461: * @context: the I/O context
462: *
463: * Close an FTP I/O channel
464: */
465: void
466: xmlIOFTPClose (void * context) {
467: xmlNanoFTPClose(context);
1.22 daniel 468: }
1.23 daniel 469: #endif /* LIBXML_FTP_ENABLED */
470:
471:
472: /**
473: * xmlRegisterInputCallbacks:
474: * @match: the xmlInputMatchCallback
475: * @open: the xmlInputOpenCallback
476: * @read: the xmlInputReadCallback
477: * @close: the xmlInputCloseCallback
478: *
479: * Register a new set of I/O callback for handling parser input.
480: *
481: * Returns the registered handler number or -1 in case of error
482: */
483: int
484: xmlRegisterInputCallbacks(xmlInputMatchCallback match,
485: xmlInputOpenCallback open, xmlInputReadCallback read,
486: xmlInputCloseCallback close) {
487: if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
488: return(-1);
489: }
490: xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match;
491: xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open;
492: xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read;
493: xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close;
494: return(xmlInputCallbackNr++);
1.22 daniel 495: }
496:
1.23 daniel 497: /**
1.27 ! daniel 498: * xmlRegisterOutputCallbacks:
! 499: * @match: the xmlOutputMatchCallback
! 500: * @open: the xmlOutputOpenCallback
! 501: * @write: the xmlOutputWriteCallback
! 502: * @close: the xmlOutputCloseCallback
! 503: *
! 504: * Register a new set of I/O callback for handling output.
! 505: *
! 506: * Returns the registered handler number or -1 in case of error
! 507: */
! 508: int
! 509: xmlRegisterOutputCallbacks(xmlOutputMatchCallback match,
! 510: xmlOutputOpenCallback open, xmlOutputWriteCallback write,
! 511: xmlOutputCloseCallback close) {
! 512: if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
! 513: return(-1);
! 514: }
! 515: xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = match;
! 516: xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = open;
! 517: xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = write;
! 518: xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = close;
! 519: return(xmlOutputCallbackNr++);
! 520: }
! 521:
! 522: /**
1.23 daniel 523: * xmlRegisterDefaultInputCallbacks:
524: *
525: * Registers the default compiled-in I/O handlers.
526: */
527: void
528: xmlRegisterDefaultInputCallbacks(void) {
529: xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
530: xmlFileRead, xmlFileClose);
531: #ifdef HAVE_ZLIB_H
532: xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
533: xmlGzfileRead, xmlGzfileClose);
534: #endif /* HAVE_ZLIB_H */
535:
536: #ifdef LIBXML_HTTP_ENABLED
537: xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
538: xmlIOHTTPRead, xmlIOHTTPClose);
539: #endif /* LIBXML_HTTP_ENABLED */
540:
541: #ifdef LIBXML_FTP_ENABLED
542: xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
543: xmlIOFTPRead, xmlIOFTPClose);
544: #endif /* LIBXML_FTP_ENABLED */
545: }
1.22 daniel 546:
1.1 daniel 547: /**
1.27 ! daniel 548: * xmlRegisterDefaultOutputCallbacks:
! 549: *
! 550: * Registers the default compiled-in I/O handlers.
! 551: */
! 552: void
! 553: xmlRegisterDefaultOutputCallbacks(void) {
! 554: xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpen,
! 555: xmlFileWrite, xmlFileClose);
! 556: /*********************************
! 557: No way a-priori to distinguish between gzipped files from
! 558: uncompressed ones except opening if existing then closing
! 559: and saving with same compression ratio ... a pain.
! 560:
! 561: #ifdef HAVE_ZLIB_H
! 562: xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
! 563: xmlGzfileWrite, xmlGzfileClose);
! 564: #endif
! 565: No HTTP PUT support yet, patches welcome
! 566:
! 567: #ifdef LIBXML_HTTP_ENABLED
! 568: xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
! 569: xmlIOHTTPWrite, xmlIOHTTPClose);
! 570: #endif
! 571:
! 572: Nor FTP PUT ....
! 573: #ifdef LIBXML_FTP_ENABLED
! 574: xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
! 575: xmlIOFTPWrite, xmlIOFTPClose);
! 576: #endif
! 577: **********************************/
! 578: }
! 579:
! 580: /**
1.1 daniel 581: * xmlAllocParserInputBuffer:
582: * @enc: the charset encoding if known
583: *
584: * Create a buffered parser input for progressive parsing
585: *
586: * Returns the new parser input or NULL
587: */
588: xmlParserInputBufferPtr
589: xmlAllocParserInputBuffer(xmlCharEncoding enc) {
590: xmlParserInputBufferPtr ret;
591:
1.8 daniel 592: ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1.1 daniel 593: if (ret == NULL) {
594: fprintf(stderr, "xmlAllocParserInputBuffer : out of memory!\n");
595: return(NULL);
596: }
1.3 veillard 597: memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1.1 daniel 598: ret->buffer = xmlBufferCreate();
1.17 daniel 599: if (ret->buffer == NULL) {
600: xmlFree(ret);
601: return(NULL);
602: }
603: ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1.1 daniel 604: ret->encoder = xmlGetCharEncodingHandler(enc);
1.26 daniel 605: if (ret->encoder != NULL)
606: ret->raw = xmlBufferCreate();
607: else
608: ret->raw = NULL;
1.23 daniel 609: ret->readcallback = NULL;
610: ret->closecallback = NULL;
611: ret->context = NULL;
1.1 daniel 612:
613: return(ret);
614: }
615:
616: /**
1.27 ! daniel 617: * xmlAllocOutputBuffer:
! 618: * @encoder: the encoding converter or NULL
! 619: *
! 620: * Create a buffered parser output
! 621: *
! 622: * Returns the new parser output or NULL
! 623: */
! 624: xmlOutputBufferPtr
! 625: xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
! 626: xmlOutputBufferPtr ret;
! 627:
! 628: ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
! 629: if (ret == NULL) {
! 630: fprintf(stderr, "xmlAllocOutputBuffer : out of memory!\n");
! 631: return(NULL);
! 632: }
! 633: memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
! 634: ret->buffer = xmlBufferCreate();
! 635: if (ret->buffer == NULL) {
! 636: xmlFree(ret);
! 637: return(NULL);
! 638: }
! 639: ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
! 640: ret->encoder = encoder;
! 641: if (encoder != NULL)
! 642: ret->raw = xmlBufferCreate();
! 643: else
! 644: ret->raw = NULL;
! 645: ret->writecallback = NULL;
! 646: ret->closecallback = NULL;
! 647: ret->context = NULL;
! 648:
! 649: return(ret);
! 650: }
! 651:
! 652: /**
1.1 daniel 653: * xmlFreeParserInputBuffer:
654: * @in: a buffered parser input
655: *
656: * Free up the memory used by a buffered parser input
657: */
658: void
659: xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1.26 daniel 660: if (in->raw) {
661: xmlBufferFree(in->raw);
662: in->raw = NULL;
663: }
1.25 daniel 664: if (in->encoder != NULL) {
665: xmlCharEncCloseFunc(in->encoder);
666: }
667: if (in->closecallback != NULL) {
668: in->closecallback(in->context);
669: }
1.1 daniel 670: if (in->buffer != NULL) {
671: xmlBufferFree(in->buffer);
672: in->buffer = NULL;
673: }
1.23 daniel 674:
1.3 veillard 675: memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
1.8 daniel 676: xmlFree(in);
1.1 daniel 677: }
678:
679: /**
680: * xmlParserInputBufferCreateFilename:
1.23 daniel 681: * @URI: a C string containing the URI or filename
1.1 daniel 682: * @enc: the charset encoding if known
683: *
684: * Create a buffered parser input for the progressive parsing of a file
685: * If filename is "-' then we use stdin as the input.
686: * Automatic support for ZLIB/Compress compressed document is provided
687: * by default if found at compile-time.
1.20 daniel 688: * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1.1 daniel 689: *
690: * Returns the new parser input or NULL
691: */
692: xmlParserInputBufferPtr
1.23 daniel 693: xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1.1 daniel 694: xmlParserInputBufferPtr ret;
1.23 daniel 695: int i;
696: void *context = NULL;
697:
698: if (xmlInputCallbackInitialized == 0)
699: xmlRegisterDefaultInputCallbacks();
1.1 daniel 700:
1.23 daniel 701: if (URI == NULL) return(NULL);
1.1 daniel 702:
1.23 daniel 703: /*
704: * Try to find one of the input accept method accepting taht scheme
705: * Go in reverse to give precedence to user defined handlers.
706: */
707: for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
708: if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
709: (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
710: context = xmlInputCallbackTable[i].opencallback(URI);
711: if (context != NULL)
712: break;
1.1 daniel 713: }
1.23 daniel 714: }
715: if (context == NULL) {
716: #ifdef DEBUG_INPUT
717: fprintf(stderr, "No input filter matching \"%s\"\n", URI);
1.1 daniel 718: #endif
1.23 daniel 719: return(NULL);
1.1 daniel 720: }
1.20 daniel 721:
722: /*
723: * Allocate the Input buffer front-end.
1.1 daniel 724: */
725: ret = xmlAllocParserInputBuffer(enc);
726: if (ret != NULL) {
1.23 daniel 727: ret->context = context;
728: ret->readcallback = xmlInputCallbackTable[i].readcallback;
729: ret->closecallback = xmlInputCallbackTable[i].closecallback;
1.1 daniel 730: }
731: return(ret);
732: }
733:
734: /**
1.27 ! daniel 735: * xmlOutputBufferCreateFilename:
! 736: * @URI: a C string containing the URI or filename
! 737: * @encoder: the encoding converter or NULL
! 738: *
! 739: * Create a buffered output for the progressive saving of a file
! 740: * If filename is "-' then we use stdout as the output.
! 741: * Automatic support for ZLIB/Compress compressed document is provided
! 742: * by default if found at compile-time.
! 743: *
! 744: * Returns the new output or NULL
! 745: */
! 746: xmlOutputBufferPtr
! 747: xmlOutputBufferCreateFilename(const char *URI,
! 748: xmlCharEncodingHandlerPtr encoder) {
! 749: xmlOutputBufferPtr ret;
! 750: int i;
! 751: void *context = NULL;
! 752:
! 753: if (xmlOutputCallbackInitialized == 0)
! 754: xmlRegisterDefaultOutputCallbacks();
! 755:
! 756: if (URI == NULL) return(NULL);
! 757:
! 758: /*
! 759: * Try to find one of the output accept method accepting taht scheme
! 760: * Go in reverse to give precedence to user defined handlers.
! 761: */
! 762: for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
! 763: if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
! 764: (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
! 765: context = xmlOutputCallbackTable[i].opencallback(URI);
! 766: if (context != NULL)
! 767: break;
! 768: }
! 769: }
! 770: if (context == NULL) {
! 771: #ifdef DEBUG_INPUT
! 772: fprintf(stderr, "No output filter matching \"%s\"\n", URI);
! 773: #endif
! 774: return(NULL);
! 775: }
! 776:
! 777: /*
! 778: * Allocate the Output buffer front-end.
! 779: */
! 780: ret = xmlAllocOutputBuffer(encoder);
! 781: if (ret != NULL) {
! 782: ret->context = context;
! 783: ret->writecallback = xmlOutputCallbackTable[i].writecallback;
! 784: ret->closecallback = xmlOutputCallbackTable[i].closecallback;
! 785: }
! 786: return(ret);
! 787: }
! 788:
! 789: /**
1.1 daniel 790: * xmlParserInputBufferCreateFile:
791: * @file: a FILE*
792: * @enc: the charset encoding if known
793: *
794: * Create a buffered parser input for the progressive parsing of a FILE *
795: * buffered C I/O
796: *
797: * Returns the new parser input or NULL
798: */
799: xmlParserInputBufferPtr
800: xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
801: xmlParserInputBufferPtr ret;
802:
1.23 daniel 803: if (xmlInputCallbackInitialized == 0)
804: xmlRegisterDefaultInputCallbacks();
805:
1.1 daniel 806: if (file == NULL) return(NULL);
807:
808: ret = xmlAllocParserInputBuffer(enc);
1.23 daniel 809: if (ret != NULL) {
810: ret->context = file;
811: ret->readcallback = xmlFileRead;
812: ret->closecallback = xmlFileClose;
813: }
1.1 daniel 814:
815: return(ret);
816: }
817:
818: /**
1.27 ! daniel 819: * xmlOutputBufferCreateFile:
! 820: * @file: a FILE*
! 821: * @encoder: the encoding converter or NULL
! 822: *
! 823: * Create a buffered output for the progressive saving to a FILE *
! 824: * buffered C I/O
! 825: *
! 826: * Returns the new parser output or NULL
! 827: */
! 828: xmlOutputBufferPtr
! 829: xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
! 830: xmlOutputBufferPtr ret;
! 831:
! 832: if (xmlOutputCallbackInitialized == 0)
! 833: xmlRegisterDefaultOutputCallbacks();
! 834:
! 835: if (file == NULL) return(NULL);
! 836:
! 837: ret = xmlAllocOutputBuffer(encoder);
! 838: if (ret != NULL) {
! 839: ret->context = file;
! 840: ret->writecallback = xmlFileWrite;
! 841: ret->closecallback = xmlFileClose;
! 842: }
! 843:
! 844: return(ret);
! 845: }
! 846:
! 847: /**
1.1 daniel 848: * xmlParserInputBufferCreateFd:
849: * @fd: a file descriptor number
850: * @enc: the charset encoding if known
851: *
852: * Create a buffered parser input for the progressive parsing for the input
853: * from a file descriptor
854: *
855: * Returns the new parser input or NULL
856: */
857: xmlParserInputBufferPtr
858: xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
859: xmlParserInputBufferPtr ret;
860:
861: if (fd < 0) return(NULL);
862:
863: ret = xmlAllocParserInputBuffer(enc);
1.23 daniel 864: if (ret != NULL) {
865: ret->context = (void *) fd;
866: ret->readcallback = xmlFdRead;
867: ret->closecallback = xmlFdClose;
868: }
1.1 daniel 869:
870: return(ret);
871: }
872:
873: /**
1.27 ! daniel 874: * xmlOutputBufferCreateFd:
! 875: * @fd: a file descriptor number
! 876: * @encoder: the encoding converter or NULL
! 877: *
! 878: * Create a buffered output for the progressive saving
! 879: * to a file descriptor
! 880: *
! 881: * Returns the new parser output or NULL
! 882: */
! 883: xmlOutputBufferPtr
! 884: xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
! 885: xmlOutputBufferPtr ret;
! 886:
! 887: if (fd < 0) return(NULL);
! 888:
! 889: ret = xmlAllocOutputBuffer(encoder);
! 890: if (ret != NULL) {
! 891: ret->context = (void *) fd;
! 892: ret->writecallback = xmlFdWrite;
! 893: ret->closecallback = xmlFdClose;
! 894: }
! 895:
! 896: return(ret);
! 897: }
! 898:
! 899: /**
1.24 daniel 900: * xmlParserInputBufferCreateIO:
901: * @ioread: an I/O read function
902: * @ioclose: an I/O close function
903: * @ioctx: an I/O handler
904: * @enc: the charset encoding if known
905: *
906: * Create a buffered parser input for the progressive parsing for the input
1.27 ! daniel 907: * from an I/O handler
1.24 daniel 908: *
909: * Returns the new parser input or NULL
910: */
911: xmlParserInputBufferPtr
912: xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
913: xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
914: xmlParserInputBufferPtr ret;
915:
916: if (ioread == NULL) return(NULL);
917:
918: ret = xmlAllocParserInputBuffer(enc);
919: if (ret != NULL) {
920: ret->context = (void *) ioctx;
921: ret->readcallback = ioread;
922: ret->closecallback = ioclose;
923: }
924:
925: return(ret);
926: }
927:
928: /**
1.27 ! daniel 929: * xmlOutputBufferCreateIO:
! 930: * @iowrite: an I/O write function
! 931: * @ioclose: an I/O close function
! 932: * @ioctx: an I/O handler
! 933: * @enc: the charset encoding if known
! 934: *
! 935: * Create a buffered output for the progressive saving
! 936: * to an I/O handler
! 937: *
! 938: * Returns the new parser output or NULL
! 939: */
! 940: xmlOutputBufferPtr
! 941: xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
! 942: xmlOutputCloseCallback ioclose, void *ioctx,
! 943: xmlCharEncodingHandlerPtr encoder) {
! 944: xmlOutputBufferPtr ret;
! 945:
! 946: if (iowrite == NULL) return(NULL);
! 947:
! 948: ret = xmlAllocOutputBuffer(encoder);
! 949: if (ret != NULL) {
! 950: ret->context = (void *) ioctx;
! 951: ret->writecallback = iowrite;
! 952: ret->closecallback = ioclose;
! 953: }
! 954:
! 955: return(ret);
! 956: }
! 957:
! 958: /**
1.14 daniel 959: * xmlParserInputBufferPush:
960: * @in: a buffered parser input
1.27 ! daniel 961: * @len: the size in bytes of the array.
1.14 daniel 962: * @buf: an char array
963: *
964: * Push the content of the arry in the input buffer
965: * This routine handle the I18N transcoding to internal UTF-8
966: * This is used when operating the parser in progressive (push) mode.
967: *
968: * Returns the number of chars read and stored in the buffer, or -1
969: * in case of error.
970: */
971: int
1.15 daniel 972: xmlParserInputBufferPush(xmlParserInputBufferPtr in, int len, const char *buf) {
1.14 daniel 973: int nbchars = 0;
974:
975: if (len < 0) return(0);
976: if (in->encoder != NULL) {
1.26 daniel 977: /*
978: * Store the data in the incoming raw buffer
979: */
980: if (in->raw == NULL) {
981: in->raw = xmlBufferCreate();
982: }
983: xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1.14 daniel 984:
985: /*
1.26 daniel 986: * convert as much as possible to the parser reading buffer.
1.14 daniel 987: */
1.26 daniel 988: nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1.20 daniel 989: if (nbchars < 0) {
990: fprintf(stderr, "xmlParserInputBufferPush: encoder error\n");
991: return(-1);
992: }
1.14 daniel 993: } else {
994: nbchars = len;
1.17 daniel 995: xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1.14 daniel 996: }
997: #ifdef DEBUG_INPUT
998: fprintf(stderr, "I/O: pushed %d chars, buffer %d/%d\n",
999: nbchars, in->buffer->use, in->buffer->size);
1000: #endif
1001: return(nbchars);
1002: }
1003:
1004: /**
1.1 daniel 1005: * xmlParserInputBufferGrow:
1006: * @in: a buffered parser input
1007: * @len: indicative value of the amount of chars to read
1008: *
1009: * Grow up the content of the input buffer, the old data are preserved
1010: * This routine handle the I18N transcoding to internal UTF-8
1.14 daniel 1011: * This routine is used when operating the parser in normal (pull) mode
1.26 daniel 1012: *
1013: * TODO: one should be able to remove one extra copy by copying directy
1014: * onto in->buffer or in->raw
1.1 daniel 1015: *
1016: * Returns the number of chars read and stored in the buffer, or -1
1017: * in case of error.
1018: */
1019: int
1020: xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1021: char *buffer = NULL;
1022: int res = 0;
1023: int nbchars = 0;
1024: int buffree;
1025:
1026: if ((len <= MINLEN) && (len != 4))
1027: len = MINLEN;
1028: buffree = in->buffer->size - in->buffer->use;
1029: if (buffree <= 0) {
1030: fprintf(stderr, "xmlParserInputBufferGrow : buffer full !\n");
1031: return(0);
1032: }
1033: if (len > buffree)
1034: len = buffree;
1035:
1.8 daniel 1036: buffer = xmlMalloc((len + 1) * sizeof(char));
1.1 daniel 1037: if (buffer == NULL) {
1038: fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
1039: return(-1);
1040: }
1.23 daniel 1041:
1042: /*
1043: * Call the read method for this I/O type.
1044: */
1045: if (in->readcallback != NULL) {
1046: res = in->readcallback(in->context, &buffer[0], len);
1.1 daniel 1047: } else {
1048: fprintf(stderr, "xmlParserInputBufferGrow : no input !\n");
1.8 daniel 1049: xmlFree(buffer);
1.1 daniel 1050: return(-1);
1051: }
1.23 daniel 1052:
1.1 daniel 1053: if (res == 0) {
1.8 daniel 1054: xmlFree(buffer);
1.1 daniel 1055: return(0);
1056: }
1057: if (res < 0) {
1058: perror ("read error");
1.8 daniel 1059: xmlFree(buffer);
1.1 daniel 1060: return(-1);
1061: }
1062: if (in->encoder != NULL) {
1.26 daniel 1063: /*
1064: * Store the data in the incoming raw buffer
1065: */
1066: if (in->raw == NULL) {
1067: in->raw = xmlBufferCreate();
1.1 daniel 1068: }
1.26 daniel 1069: xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
1.20 daniel 1070:
1071: /*
1.26 daniel 1072: * convert as much as possible to the parser reading buffer.
1.20 daniel 1073: */
1.26 daniel 1074: nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1075: if (nbchars < 0) {
1076: fprintf(stderr, "xmlParserInputBufferGrow: encoder error\n");
1077: return(-1);
1.20 daniel 1078: }
1.1 daniel 1079: } else {
1080: nbchars = res;
1.3 veillard 1081: buffer[nbchars] = 0;
1.13 daniel 1082: xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
1.1 daniel 1083: }
1084: #ifdef DEBUG_INPUT
1085: fprintf(stderr, "I/O: read %d chars, buffer %d/%d\n",
1086: nbchars, in->buffer->use, in->buffer->size);
1087: #endif
1.8 daniel 1088: xmlFree(buffer);
1.1 daniel 1089: return(nbchars);
1090: }
1091:
1092: /**
1093: * xmlParserInputBufferRead:
1094: * @in: a buffered parser input
1095: * @len: indicative value of the amount of chars to read
1096: *
1097: * Refresh the content of the input buffer, the old data are considered
1098: * consumed
1099: * This routine handle the I18N transcoding to internal UTF-8
1100: *
1101: * Returns the number of chars read and stored in the buffer, or -1
1102: * in case of error.
1103: */
1104: int
1105: xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
1106: /* xmlBufferEmpty(in->buffer); */
1.23 daniel 1107: if (in->readcallback != NULL)
1.17 daniel 1108: return(xmlParserInputBufferGrow(in, len));
1109: else
1.27 ! daniel 1110: return(-1);
! 1111: }
! 1112:
! 1113: /**
! 1114: * xmlOutputBufferWrite:
! 1115: * @out: a buffered parser output
! 1116: * @len: the size in bytes of the array.
! 1117: * @buf: an char array
! 1118: *
! 1119: * Write the content of the array in the output I/O buffer
! 1120: * This routine handle the I18N transcoding from internal UTF-8
! 1121: * The buffer is lossless, i.e. will store in case of partial
! 1122: * or delayed writes.
! 1123: *
! 1124: * Returns the number of chars immediately written, or -1
! 1125: * in case of error.
! 1126: */
! 1127: int
! 1128: xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
! 1129: int nbchars = 0, ret;
! 1130:
! 1131: if (len < 0) return(0);
! 1132:
! 1133: /*
! 1134: * first handle encoding stuff.
! 1135: */
! 1136: if (out->encoder != NULL) {
! 1137: /*
! 1138: * Store the data in the incoming raw buffer
! 1139: */
! 1140: if (out->raw == NULL) {
! 1141: out->raw = xmlBufferCreate();
! 1142: }
! 1143: xmlBufferAdd(out->raw, (const xmlChar *) buf, len);
! 1144:
! 1145: if (out->raw->use < MINLEN)
! 1146: return(0);
! 1147:
! 1148: /*
! 1149: * convert as much as possible to the parser reading buffer.
! 1150: */
! 1151: nbchars = xmlCharEncOutFunc(out->encoder, out->buffer, out->raw);
! 1152: if (nbchars < 0) {
! 1153: fprintf(stderr, "xmlOutputBufferWrite: encoder error\n");
! 1154: return(-1);
! 1155: }
! 1156: } else {
! 1157: xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
! 1158: }
! 1159: nbchars = out->buffer->use;
! 1160: if (nbchars < MINLEN)
! 1161: return(0);
! 1162:
! 1163: /*
! 1164: * second write the stuff to the I/O channel
! 1165: */
! 1166: ret = out->writecallback(out->context,
! 1167: (const char *)out->buffer->content, nbchars);
! 1168: if (ret >= 0)
! 1169: xmlBufferShrink(out->buffer, nbchars);
! 1170: if (ret < 0) {
! 1171: fprintf(stderr, "I/O: error %d writing %d bytes\n", ret, nbchars);
! 1172: return(ret);
! 1173: }
! 1174:
! 1175: #ifdef DEBUG_INPUT
! 1176: fprintf(stderr, "I/O: wrote %d chars\n", ret);
! 1177: #endif
! 1178: return(nbchars);
1.4 daniel 1179: }
1180:
1181: /*
1182: * xmlParserGetDirectory:
1183: * @filename: the path to a file
1184: *
1185: * lookup the directory for that file
1186: *
1187: * Returns a new allocated string containing the directory, or NULL.
1188: */
1189: char *
1190: xmlParserGetDirectory(const char *filename) {
1191: char *ret = NULL;
1192: char dir[1024];
1193: char *cur;
1194: char sep = '/';
1.23 daniel 1195:
1196: if (xmlInputCallbackInitialized == 0)
1197: xmlRegisterDefaultInputCallbacks();
1.4 daniel 1198:
1199: if (filename == NULL) return(NULL);
1200: #ifdef WIN32
1201: sep = '\\';
1202: #endif
1203:
1204: strncpy(dir, filename, 1023);
1205: dir[1023] = 0;
1206: cur = &dir[strlen(dir)];
1207: while (cur > dir) {
1208: if (*cur == sep) break;
1209: cur --;
1210: }
1211: if (*cur == sep) {
1212: if (cur == dir) dir[1] = 0;
1213: else *cur = 0;
1.8 daniel 1214: ret = xmlMemStrdup(dir);
1.4 daniel 1215: } else {
1216: if (getcwd(dir, 1024) != NULL) {
1217: dir[1023] = 0;
1.8 daniel 1218: ret = xmlMemStrdup(dir);
1.4 daniel 1219: }
1220: }
1221: return(ret);
1.5 daniel 1222: }
1223:
1224: /****************************************************************
1225: * *
1226: * External entities loading *
1227: * *
1228: ****************************************************************/
1229:
1230: /*
1231: * xmlDefaultExternalEntityLoader:
1232: * @URL: the URL for the entity to load
1233: * @ID: the System ID for the entity to load
1.18 daniel 1234: * @ctxt: the context in which the entity is called or NULL
1.5 daniel 1235: *
1236: * By default we don't load external entitites, yet.
1237: *
1238: * Returns a new allocated xmlParserInputPtr, or NULL.
1239: */
1240: static
1241: xmlParserInputPtr
1242: xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
1.18 daniel 1243: xmlParserCtxtPtr ctxt) {
1244: xmlParserInputPtr ret = NULL;
1.5 daniel 1245: #ifdef DEBUG_EXTERNAL_ENTITIES
1246: fprintf(stderr, "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
1247: #endif
1.18 daniel 1248: if (URL == NULL) {
1249: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1250: ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n",
1251: ID);
1252: return(NULL);
1253: }
1254: ret = xmlNewInputFromFile(ctxt, URL);
1255: if (ret == NULL) {
1256: if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
1257: ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n",
1258: URL);
1259: }
1260: return(ret);
1.5 daniel 1261: }
1262:
1263: static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
1264: xmlDefaultExternalEntityLoader;
1265:
1266: /*
1267: * xmlSetExternalEntityLoader:
1268: * @f: the new entity resolver function
1269: *
1270: * Changes the defaultexternal entity resolver function for the application
1271: */
1272: void
1273: xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
1274: xmlCurrentExternalEntityLoader = f;
1275: }
1276:
1277: /*
1278: * xmlGetExternalEntityLoader:
1279: *
1280: * Get the default external entity resolver function for the application
1281: *
1282: * Returns the xmlExternalEntityLoader function pointer
1283: */
1284: xmlExternalEntityLoader
1285: xmlGetExternalEntityLoader(void) {
1286: return(xmlCurrentExternalEntityLoader);
1287: }
1288:
1289: /*
1290: * xmlLoadExternalEntity:
1291: * @URL: the URL for the entity to load
1292: * @ID: the System ID for the entity to load
1.18 daniel 1293: * @ctxt: the context in which the entity is called or NULL
1.5 daniel 1294: *
1295: * Load an external entity, note that the use of this function for
1296: * unparsed entities may generate problems
1.6 daniel 1297: * TODO: a more generic External entitiy API must be designed
1.5 daniel 1298: *
1299: * Returns the xmlParserInputPtr or NULL
1300: */
1301: xmlParserInputPtr
1302: xmlLoadExternalEntity(const char *URL, const char *ID,
1.18 daniel 1303: xmlParserCtxtPtr ctxt) {
1304: return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
1.1 daniel 1305: }
1306:
Webmaster