blob: d25a07b045558b008ea1b78fc2df926f4614ede8 [file] [log] [blame]
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel.Veillard@w3.org
7 */
8
Daniel Veillardb05deb71999-08-10 19:04:08 +00009/*
10 * TODO: plug-in a generic transfer library, like libwww if available
11 */
12
Daniel Veillarde2d034d1999-07-27 19:52:06 +000013#include "config.h"
14
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <malloc.h>
19#ifdef HAVE_UNISTD_H
20#include <unistd.h>
21#endif
22#ifdef HAVE_ZLIB_H
23#include <zlib.h>
24#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000025#include <string.h>
Daniel Veillarde2d034d1999-07-27 19:52:06 +000026
27#include "xmlIO.h"
28
29/* #define DEBUG_INPUT */
30/* #define VERBOSE_FAILURE */
31
32#ifdef DEBUG_INPUT
33#define MINLEN 40
34#else
35#define MINLEN 4000
36#endif
37
38/**
39 * xmlAllocParserInputBuffer:
40 * @enc: the charset encoding if known
41 *
42 * Create a buffered parser input for progressive parsing
43 *
44 * Returns the new parser input or NULL
45 */
46xmlParserInputBufferPtr
47xmlAllocParserInputBuffer(xmlCharEncoding enc) {
48 xmlParserInputBufferPtr ret;
49
50 ret = (xmlParserInputBufferPtr) malloc(sizeof(xmlParserInputBuffer));
51 if (ret == NULL) {
52 fprintf(stderr, "xmlAllocParserInputBuffer : out of memory!\n");
53 return(NULL);
54 }
55 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
56 ret->buffer = xmlBufferCreate();
57 ret->encoder = xmlGetCharEncodingHandler(enc);
58 ret->fd = -1;
59
60 return(ret);
61}
62
63/**
64 * xmlFreeParserInputBuffer:
65 * @in: a buffered parser input
66 *
67 * Free up the memory used by a buffered parser input
68 */
69void
70xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
71 if (in->buffer != NULL) {
72 xmlBufferFree(in->buffer);
73 in->buffer = NULL;
74 }
75#ifdef HAVE_ZLIB_H
76 if (in->gzfile != NULL)
77 gzclose(in->gzfile);
78#endif
79 if (in->fd >= 0)
80 close(in->fd);
81 memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
82 free(in);
83}
84
85/**
86 * xmlParserInputBufferCreateFilename:
87 * @filename: a C string containing the filename
88 * @enc: the charset encoding if known
89 *
90 * Create a buffered parser input for the progressive parsing of a file
91 * If filename is "-' then we use stdin as the input.
92 * Automatic support for ZLIB/Compress compressed document is provided
93 * by default if found at compile-time.
94 *
95 * Returns the new parser input or NULL
96 */
97xmlParserInputBufferPtr
98xmlParserInputBufferCreateFilename(const char *filename, xmlCharEncoding enc) {
99 xmlParserInputBufferPtr ret;
100#ifdef HAVE_ZLIB_H
101 gzFile input;
102#else
103 int input = -1;
104#endif
105
106 if (filename == NULL) return(NULL);
107
108 if (!strcmp(filename, "-")) {
109#ifdef HAVE_ZLIB_H
110 input = gzdopen (fileno(stdin), "r");
111 if (input == NULL) {
112#ifdef VERBOSE_FAILURE
113 fprintf (stderr, "Cannot read from stdin\n");
114 perror ("gzdopen failed");
115#endif
116 return(NULL);
117 }
118#else
119#ifdef WIN32
120 input = -1;
121#else
122 input = fileno(stdin);
123#endif
124 if (input < 0) {
125#ifdef VERBOSE_FAILURE
126 fprintf (stderr, "Cannot read from stdin\n");
127 perror ("open failed");
128#endif
129 return(NULL);
130 }
131#endif
132 } else {
133#ifdef HAVE_ZLIB_H
134 input = gzopen (filename, "r");
135 if (input == NULL) {
136#ifdef VERBOSE_FAILURE
137 fprintf (stderr, "Cannot read file %s :\n", filename);
138 perror ("gzopen failed");
139#endif
140 return(NULL);
141 }
142#else
143#ifdef WIN32
144 input = _open (filename, O_RDONLY | _O_BINARY);
145#else
146 input = open (filename, O_RDONLY);
147#endif
148 if (input < 0) {
149#ifdef VERBOSE_FAILURE
150 fprintf (stderr, "Cannot read file %s :\n", filename);
151 perror ("open failed");
152#endif
153 return(NULL);
154 }
155#endif
156 }
157 /*
158 * TODO : get the 4 first bytes and
159 * if enc == XML_CHAR_ENCODING_NONE
160 * plug some encoding conversion routines here. !!!
161 * enc = xmlDetectCharEncoding(buffer);
162 */
163
164 ret = xmlAllocParserInputBuffer(enc);
165 if (ret != NULL) {
166#ifdef HAVE_ZLIB_H
167 ret->gzfile = input;
168#else
169 ret->fd = input;
170#endif
171 }
172 xmlParserInputBufferRead(ret, 4);
173
174 return(ret);
175}
176
177/**
178 * xmlParserInputBufferCreateFile:
179 * @file: a FILE*
180 * @enc: the charset encoding if known
181 *
182 * Create a buffered parser input for the progressive parsing of a FILE *
183 * buffered C I/O
184 *
185 * Returns the new parser input or NULL
186 */
187xmlParserInputBufferPtr
188xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
189 xmlParserInputBufferPtr ret;
190
191 if (file == NULL) return(NULL);
192
193 ret = xmlAllocParserInputBuffer(enc);
194 if (ret != NULL)
195 ret->file = file;
196
197 return(ret);
198}
199
200/**
201 * xmlParserInputBufferCreateFd:
202 * @fd: a file descriptor number
203 * @enc: the charset encoding if known
204 *
205 * Create a buffered parser input for the progressive parsing for the input
206 * from a file descriptor
207 *
208 * Returns the new parser input or NULL
209 */
210xmlParserInputBufferPtr
211xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
212 xmlParserInputBufferPtr ret;
213
214 if (fd < 0) return(NULL);
215
216 ret = xmlAllocParserInputBuffer(enc);
217 if (ret != NULL)
218 ret->fd = fd;
219
220 return(ret);
221}
222
223/**
224 * xmlParserInputBufferGrow:
225 * @in: a buffered parser input
226 * @len: indicative value of the amount of chars to read
227 *
228 * Grow up the content of the input buffer, the old data are preserved
229 * This routine handle the I18N transcoding to internal UTF-8
230 * TODO: one should be able to remove one copy
231 *
232 * Returns the number of chars read and stored in the buffer, or -1
233 * in case of error.
234 */
235int
236xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
237 char *buffer = NULL;
238#ifdef HAVE_ZLIB_H
239 gzFile input = (gzFile) in->gzfile;
240#endif
241 int res = 0;
242 int nbchars = 0;
243 int buffree;
244
245 if ((len <= MINLEN) && (len != 4))
246 len = MINLEN;
247 buffree = in->buffer->size - in->buffer->use;
248 if (buffree <= 0) {
249 fprintf(stderr, "xmlParserInputBufferGrow : buffer full !\n");
250 return(0);
251 }
252 if (len > buffree)
253 len = buffree;
254
255 buffer = malloc((len + 1) * sizeof(char));
256 if (buffer == NULL) {
257 fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
258 return(-1);
259 }
260 if (in->file != NULL) {
261 res = fread(&buffer[0], 1, len, in->file);
262#ifdef HAVE_ZLIB_H
263 } else if (in->gzfile != NULL) {
264 res = gzread(input, &buffer[0], len);
265#endif
266 } else if (in->fd >= 0) {
267 res = read(in->fd, &buffer[0], len);
268 } else {
269 fprintf(stderr, "xmlParserInputBufferGrow : no input !\n");
270 free(buffer);
271 return(-1);
272 }
273 if (res == 0) {
274 free(buffer);
275 return(0);
276 }
277 if (res < 0) {
278 perror ("read error");
279 free(buffer);
280 return(-1);
281 }
282 if (in->encoder != NULL) {
283 CHAR *buf;
284
285 buf = (CHAR *) malloc((res + 1) * 2 * sizeof(CHAR));
286 if (buf == NULL) {
287 fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
288 free(buffer);
289 return(-1);
290 }
291 nbchars = in->encoder->input(buf, (res + 1) * 2 * sizeof(CHAR),
292 buffer, res);
293 buf[nbchars] = 0;
294 xmlBufferAdd(in->buffer, (CHAR *) buf, nbchars);
295 free(buf);
296 } else {
297 nbchars = res;
298 buffer[nbchars] = 0;
299 xmlBufferAdd(in->buffer, (CHAR *) buffer, nbchars);
300 }
301#ifdef DEBUG_INPUT
302 fprintf(stderr, "I/O: read %d chars, buffer %d/%d\n",
303 nbchars, in->buffer->use, in->buffer->size);
304#endif
305 free(buffer);
306 return(nbchars);
307}
308
309/**
310 * xmlParserInputBufferRead:
311 * @in: a buffered parser input
312 * @len: indicative value of the amount of chars to read
313 *
314 * Refresh the content of the input buffer, the old data are considered
315 * consumed
316 * This routine handle the I18N transcoding to internal UTF-8
317 *
318 * Returns the number of chars read and stored in the buffer, or -1
319 * in case of error.
320 */
321int
322xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
323 /* xmlBufferEmpty(in->buffer); */
324 return(xmlParserInputBufferGrow(in, len));
325}
326
Daniel Veillardb05deb71999-08-10 19:04:08 +0000327/*
328 * xmlParserGetDirectory:
329 * @filename: the path to a file
330 *
331 * lookup the directory for that file
332 *
333 * Returns a new allocated string containing the directory, or NULL.
334 */
335char *
336xmlParserGetDirectory(const char *filename) {
337 char *ret = NULL;
338 char dir[1024];
339 char *cur;
340 char sep = '/';
341
342 if (filename == NULL) return(NULL);
343#ifdef WIN32
344 sep = '\\';
345#endif
346
347 strncpy(dir, filename, 1023);
348 dir[1023] = 0;
349 cur = &dir[strlen(dir)];
350 while (cur > dir) {
351 if (*cur == sep) break;
352 cur --;
353 }
354 if (*cur == sep) {
355 if (cur == dir) dir[1] = 0;
356 else *cur = 0;
357 ret = strdup(dir);
358 } else {
359 if (getcwd(dir, 1024) != NULL) {
360 dir[1023] = 0;
361 ret = strdup(dir);
362 }
363 }
364 return(ret);
365}
366