Annotation of XML/xmlIO.c, revision 1.12
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
10: #define HAVE_FCNTL_H
11: #include <io.h>
12: #else
1.12 ! daniel 13: #include "config.h"
1.10 daniel 14: #endif
15:
16: #include <stdio.h>
17: #include <string.h>
1.1 daniel 18:
1.10 daniel 19: #ifdef HAVE_SYS_TYPES_H
1.1 daniel 20: #include <sys/types.h>
1.10 daniel 21: #endif
22: #ifdef HAVE_SYS_STAT_H
1.1 daniel 23: #include <sys/stat.h>
1.10 daniel 24: #endif
25: #ifdef HAVE_FCNTL_H
1.1 daniel 26: #include <fcntl.h>
1.10 daniel 27: #endif
1.1 daniel 28: #ifdef HAVE_UNISTD_H
29: #include <unistd.h>
30: #endif
1.10 daniel 31: #ifdef HAVE_STDLIB_H
32: #include <stdlib.h>
33: #endif
1.1 daniel 34: #ifdef HAVE_ZLIB_H
35: #include <zlib.h>
36: #endif
37:
1.8 daniel 38: #include "xmlmemory.h"
1.5 daniel 39: #include "parser.h"
1.1 daniel 40: #include "xmlIO.h"
1.9 daniel 41: #include "nanohttp.h"
1.1 daniel 42:
43: /* #define DEBUG_INPUT */
1.2 daniel 44: /* #define VERBOSE_FAILURE */
1.5 daniel 45: /* #define DEBUG_EXTERNAL_ENTITIES */
1.1 daniel 46:
47: #ifdef DEBUG_INPUT
48: #define MINLEN 40
49: #else
50: #define MINLEN 4000
51: #endif
52:
53: /**
54: * xmlAllocParserInputBuffer:
55: * @enc: the charset encoding if known
56: *
57: * Create a buffered parser input for progressive parsing
58: *
59: * Returns the new parser input or NULL
60: */
61: xmlParserInputBufferPtr
62: xmlAllocParserInputBuffer(xmlCharEncoding enc) {
63: xmlParserInputBufferPtr ret;
64:
1.8 daniel 65: ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1.1 daniel 66: if (ret == NULL) {
67: fprintf(stderr, "xmlAllocParserInputBuffer : out of memory!\n");
68: return(NULL);
69: }
1.3 veillard 70: memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1.1 daniel 71: ret->buffer = xmlBufferCreate();
72: ret->encoder = xmlGetCharEncodingHandler(enc);
73: ret->fd = -1;
1.11 daniel 74: ret->netIO = NULL;
1.1 daniel 75:
76: return(ret);
77: }
78:
79: /**
80: * xmlFreeParserInputBuffer:
81: * @in: a buffered parser input
82: *
83: * Free up the memory used by a buffered parser input
84: */
85: void
86: xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
87: if (in->buffer != NULL) {
88: xmlBufferFree(in->buffer);
89: in->buffer = NULL;
90: }
91: #ifdef HAVE_ZLIB_H
92: if (in->gzfile != NULL)
93: gzclose(in->gzfile);
94: #endif
1.11 daniel 95: if (in->netIO != NULL)
96: xmlNanoHTTPClose(in->netIO);
1.1 daniel 97: if (in->fd >= 0)
98: close(in->fd);
1.3 veillard 99: memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
1.8 daniel 100: xmlFree(in);
1.1 daniel 101: }
102:
103: /**
104: * xmlParserInputBufferCreateFilename:
105: * @filename: a C string containing the filename
106: * @enc: the charset encoding if known
107: *
108: * Create a buffered parser input for the progressive parsing of a file
109: * If filename is "-' then we use stdin as the input.
110: * Automatic support for ZLIB/Compress compressed document is provided
111: * by default if found at compile-time.
112: *
113: * Returns the new parser input or NULL
114: */
115: xmlParserInputBufferPtr
116: xmlParserInputBufferCreateFilename(const char *filename, xmlCharEncoding enc) {
117: xmlParserInputBufferPtr ret;
118: #ifdef HAVE_ZLIB_H
1.12 ! daniel 119: gzFile input = 0;
1.1 daniel 120: #else
121: int input = -1;
122: #endif
1.11 daniel 123: void *netIO = NULL;
1.1 daniel 124:
125: if (filename == NULL) return(NULL);
126:
1.11 daniel 127: if (!strncmp(filename, "http://", 7)) {
128: netIO = xmlNanoHTTPOpen(filename, NULL);
129: if (netIO == NULL) {
130: #ifdef VERBOSE_FAILURE
131: fprintf (stderr, "Cannot read URL %s\n", filename);
132: perror ("xmlNanoHTTPOpen failed");
133: #endif
134: return(NULL);
135: }
136: } else if (!strcmp(filename, "-")) {
1.1 daniel 137: #ifdef HAVE_ZLIB_H
138: input = gzdopen (fileno(stdin), "r");
139: if (input == NULL) {
1.2 daniel 140: #ifdef VERBOSE_FAILURE
1.1 daniel 141: fprintf (stderr, "Cannot read from stdin\n");
142: perror ("gzdopen failed");
1.2 daniel 143: #endif
1.1 daniel 144: return(NULL);
145: }
146: #else
147: #ifdef WIN32
148: input = -1;
149: #else
150: input = fileno(stdin);
151: #endif
152: if (input < 0) {
1.2 daniel 153: #ifdef VERBOSE_FAILURE
1.1 daniel 154: fprintf (stderr, "Cannot read from stdin\n");
155: perror ("open failed");
1.2 daniel 156: #endif
157: return(NULL);
1.1 daniel 158: }
159: #endif
160: } else {
161: #ifdef HAVE_ZLIB_H
162: input = gzopen (filename, "r");
163: if (input == NULL) {
1.2 daniel 164: #ifdef VERBOSE_FAILURE
1.1 daniel 165: fprintf (stderr, "Cannot read file %s :\n", filename);
166: perror ("gzopen failed");
1.2 daniel 167: #endif
1.1 daniel 168: return(NULL);
169: }
170: #else
171: #ifdef WIN32
172: input = _open (filename, O_RDONLY | _O_BINARY);
173: #else
174: input = open (filename, O_RDONLY);
175: #endif
176: if (input < 0) {
1.2 daniel 177: #ifdef VERBOSE_FAILURE
1.1 daniel 178: fprintf (stderr, "Cannot read file %s :\n", filename);
179: perror ("open failed");
1.2 daniel 180: #endif
1.1 daniel 181: return(NULL);
182: }
183: #endif
184: }
185: /*
1.6 daniel 186: * TODO : get the 4 first bytes and decode the charset
1.1 daniel 187: * if enc == XML_CHAR_ENCODING_NONE
188: * plug some encoding conversion routines here. !!!
189: * enc = xmlDetectCharEncoding(buffer);
190: */
191:
192: ret = xmlAllocParserInputBuffer(enc);
193: if (ret != NULL) {
194: #ifdef HAVE_ZLIB_H
195: ret->gzfile = input;
196: #else
197: ret->fd = input;
198: #endif
1.11 daniel 199: ret->netIO = netIO;
1.1 daniel 200: }
201: xmlParserInputBufferRead(ret, 4);
202:
203: return(ret);
204: }
205:
206: /**
207: * xmlParserInputBufferCreateFile:
208: * @file: a FILE*
209: * @enc: the charset encoding if known
210: *
211: * Create a buffered parser input for the progressive parsing of a FILE *
212: * buffered C I/O
213: *
214: * Returns the new parser input or NULL
215: */
216: xmlParserInputBufferPtr
217: xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
218: xmlParserInputBufferPtr ret;
219:
220: if (file == NULL) return(NULL);
221:
222: ret = xmlAllocParserInputBuffer(enc);
223: if (ret != NULL)
224: ret->file = file;
225:
226: return(ret);
227: }
228:
229: /**
230: * xmlParserInputBufferCreateFd:
231: * @fd: a file descriptor number
232: * @enc: the charset encoding if known
233: *
234: * Create a buffered parser input for the progressive parsing for the input
235: * from a file descriptor
236: *
237: * Returns the new parser input or NULL
238: */
239: xmlParserInputBufferPtr
240: xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
241: xmlParserInputBufferPtr ret;
242:
243: if (fd < 0) return(NULL);
244:
245: ret = xmlAllocParserInputBuffer(enc);
246: if (ret != NULL)
247: ret->fd = fd;
248:
249: return(ret);
250: }
251:
252: /**
253: * xmlParserInputBufferGrow:
254: * @in: a buffered parser input
255: * @len: indicative value of the amount of chars to read
256: *
257: * Grow up the content of the input buffer, the old data are preserved
258: * This routine handle the I18N transcoding to internal UTF-8
1.7 daniel 259: * TODO: one should be able to remove one extra copy
1.1 daniel 260: *
261: * Returns the number of chars read and stored in the buffer, or -1
262: * in case of error.
263: */
264: int
265: xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
266: char *buffer = NULL;
267: #ifdef HAVE_ZLIB_H
268: gzFile input = (gzFile) in->gzfile;
269: #endif
270: int res = 0;
271: int nbchars = 0;
272: int buffree;
273:
274: if ((len <= MINLEN) && (len != 4))
275: len = MINLEN;
276: buffree = in->buffer->size - in->buffer->use;
277: if (buffree <= 0) {
278: fprintf(stderr, "xmlParserInputBufferGrow : buffer full !\n");
279: return(0);
280: }
281: if (len > buffree)
282: len = buffree;
283:
1.8 daniel 284: buffer = xmlMalloc((len + 1) * sizeof(char));
1.1 daniel 285: if (buffer == NULL) {
286: fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
287: return(-1);
288: }
1.11 daniel 289: if (in->netIO != NULL) {
290: res = xmlNanoHTTPRead(in->netIO, &buffer[0], len);
291: } else if (in->file != NULL) {
1.1 daniel 292: res = fread(&buffer[0], 1, len, in->file);
293: #ifdef HAVE_ZLIB_H
294: } else if (in->gzfile != NULL) {
295: res = gzread(input, &buffer[0], len);
296: #endif
297: } else if (in->fd >= 0) {
298: res = read(in->fd, &buffer[0], len);
299: } else {
300: fprintf(stderr, "xmlParserInputBufferGrow : no input !\n");
1.8 daniel 301: xmlFree(buffer);
1.1 daniel 302: return(-1);
303: }
304: if (res == 0) {
1.8 daniel 305: xmlFree(buffer);
1.1 daniel 306: return(0);
307: }
308: if (res < 0) {
309: perror ("read error");
1.8 daniel 310: xmlFree(buffer);
1.1 daniel 311: return(-1);
312: }
313: if (in->encoder != NULL) {
314: CHAR *buf;
315:
1.8 daniel 316: buf = (CHAR *) xmlMalloc((res + 1) * 2 * sizeof(CHAR));
1.1 daniel 317: if (buf == NULL) {
318: fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
1.8 daniel 319: xmlFree(buffer);
1.1 daniel 320: return(-1);
321: }
322: nbchars = in->encoder->input(buf, (res + 1) * 2 * sizeof(CHAR),
1.6 daniel 323: BAD_CAST buffer, res);
1.3 veillard 324: buf[nbchars] = 0;
1.1 daniel 325: xmlBufferAdd(in->buffer, (CHAR *) buf, nbchars);
1.8 daniel 326: xmlFree(buf);
1.1 daniel 327: } else {
328: nbchars = res;
1.3 veillard 329: buffer[nbchars] = 0;
1.1 daniel 330: xmlBufferAdd(in->buffer, (CHAR *) buffer, nbchars);
331: }
332: #ifdef DEBUG_INPUT
333: fprintf(stderr, "I/O: read %d chars, buffer %d/%d\n",
334: nbchars, in->buffer->use, in->buffer->size);
335: #endif
1.8 daniel 336: xmlFree(buffer);
1.1 daniel 337: return(nbchars);
338: }
339:
340: /**
341: * xmlParserInputBufferRead:
342: * @in: a buffered parser input
343: * @len: indicative value of the amount of chars to read
344: *
345: * Refresh the content of the input buffer, the old data are considered
346: * consumed
347: * This routine handle the I18N transcoding to internal UTF-8
348: *
349: * Returns the number of chars read and stored in the buffer, or -1
350: * in case of error.
351: */
352: int
353: xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
354: /* xmlBufferEmpty(in->buffer); */
355: return(xmlParserInputBufferGrow(in, len));
1.4 daniel 356: }
357:
358: /*
359: * xmlParserGetDirectory:
360: * @filename: the path to a file
361: *
362: * lookup the directory for that file
363: *
364: * Returns a new allocated string containing the directory, or NULL.
365: */
366: char *
367: xmlParserGetDirectory(const char *filename) {
368: char *ret = NULL;
369: char dir[1024];
370: char *cur;
371: char sep = '/';
372:
373: if (filename == NULL) return(NULL);
374: #ifdef WIN32
375: sep = '\\';
376: #endif
377:
378: strncpy(dir, filename, 1023);
379: dir[1023] = 0;
380: cur = &dir[strlen(dir)];
381: while (cur > dir) {
382: if (*cur == sep) break;
383: cur --;
384: }
385: if (*cur == sep) {
386: if (cur == dir) dir[1] = 0;
387: else *cur = 0;
1.8 daniel 388: ret = xmlMemStrdup(dir);
1.4 daniel 389: } else {
390: if (getcwd(dir, 1024) != NULL) {
391: dir[1023] = 0;
1.8 daniel 392: ret = xmlMemStrdup(dir);
1.4 daniel 393: }
394: }
395: return(ret);
1.5 daniel 396: }
397:
398: /****************************************************************
399: * *
400: * External entities loading *
401: * *
402: ****************************************************************/
403:
404: /*
405: * xmlDefaultExternalEntityLoader:
406: * @URL: the URL for the entity to load
407: * @ID: the System ID for the entity to load
408: * @context: the context in which the entity is called or NULL
409: *
410: * By default we don't load external entitites, yet.
411: * TODO: get a sample http implementation and scan for existing one
412: * at compile time.
413: *
414: * Returns a new allocated xmlParserInputPtr, or NULL.
415: */
416: static
417: xmlParserInputPtr
418: xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
419: xmlParserInputPtr context) {
420: #ifdef DEBUG_EXTERNAL_ENTITIES
421: fprintf(stderr, "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
422: #endif
423: return(NULL);
424: }
425:
426: static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
427: xmlDefaultExternalEntityLoader;
428:
429: /*
430: * xmlSetExternalEntityLoader:
431: * @f: the new entity resolver function
432: *
433: * Changes the defaultexternal entity resolver function for the application
434: */
435: void
436: xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
437: xmlCurrentExternalEntityLoader = f;
438: }
439:
440: /*
441: * xmlGetExternalEntityLoader:
442: *
443: * Get the default external entity resolver function for the application
444: *
445: * Returns the xmlExternalEntityLoader function pointer
446: */
447: xmlExternalEntityLoader
448: xmlGetExternalEntityLoader(void) {
449: return(xmlCurrentExternalEntityLoader);
450: }
451:
452: /*
453: * xmlLoadExternalEntity:
454: * @URL: the URL for the entity to load
455: * @ID: the System ID for the entity to load
456: * @context: the context in which the entity is called or NULL
457: *
458: * Load an external entity, note that the use of this function for
459: * unparsed entities may generate problems
1.6 daniel 460: * TODO: a more generic External entitiy API must be designed
1.5 daniel 461: *
462: * Returns the xmlParserInputPtr or NULL
463: */
464: xmlParserInputPtr
465: xmlLoadExternalEntity(const char *URL, const char *ID,
466: xmlParserInputPtr context) {
467: return(xmlCurrentExternalEntityLoader(URL, ID, context));
1.1 daniel 468: }
469:
Webmaster