diff options
Diffstat (limited to 'gzlib.c')
-rw-r--r-- | gzlib.c | 513 |
1 files changed, 513 insertions, 0 deletions
@@ -0,0 +1,513 @@ | |||
1 | /* gzlib.c -- zlib functions common to reading and writing gzip files | ||
2 | * Copyright (C) 2004, 2010 Mark Adler | ||
3 | * For conditions of distribution and use, see copyright notice in zlib.h | ||
4 | */ | ||
5 | |||
6 | #ifndef OLD_GZIO | ||
7 | |||
8 | #include "gzguts.h" | ||
9 | |||
10 | #ifdef _LARGEFILE64_SOURCE | ||
11 | # define LSEEK lseek64 | ||
12 | #else | ||
13 | # define LSEEK lseek | ||
14 | #endif | ||
15 | |||
16 | /* Local functions */ | ||
17 | local void gz_reset OF((gz_statep)); | ||
18 | local gzFile gz_open OF((const char *, int, const char *, int)); | ||
19 | |||
20 | #if defined UNDER_CE && defined NO_ERRNO_H | ||
21 | local char *strwinerror OF((DWORD error)); | ||
22 | |||
23 | # include <windows.h> | ||
24 | |||
25 | /* Map the Windows error number in ERROR to a locale-dependent error | ||
26 | message string and return a pointer to it. Typically, the values | ||
27 | for ERROR come from GetLastError. | ||
28 | |||
29 | The string pointed to shall not be modified by the application, | ||
30 | but may be overwritten by a subsequent call to strwinerror | ||
31 | |||
32 | The strwinerror function does not change the current setting | ||
33 | of GetLastError. */ | ||
34 | |||
35 | local char *strwinerror (error) | ||
36 | DWORD error; | ||
37 | { | ||
38 | static char buf[1024]; | ||
39 | |||
40 | wchar_t *msgbuf; | ||
41 | DWORD lasterr = GetLastError(); | ||
42 | DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | ||
43 | | FORMAT_MESSAGE_ALLOCATE_BUFFER, | ||
44 | NULL, | ||
45 | error, | ||
46 | 0, /* Default language */ | ||
47 | (LPVOID)&msgbuf, | ||
48 | 0, | ||
49 | NULL); | ||
50 | if (chars != 0) { | ||
51 | /* If there is an \r\n appended, zap it. */ | ||
52 | if (chars >= 2 | ||
53 | && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { | ||
54 | chars -= 2; | ||
55 | msgbuf[chars] = 0; | ||
56 | } | ||
57 | |||
58 | if (chars > sizeof (buf) - 1) { | ||
59 | chars = sizeof (buf) - 1; | ||
60 | msgbuf[chars] = 0; | ||
61 | } | ||
62 | |||
63 | wcstombs(buf, msgbuf, chars + 1); | ||
64 | LocalFree(msgbuf); | ||
65 | } | ||
66 | else { | ||
67 | sprintf(buf, "unknown win32 error (%ld)", error); | ||
68 | } | ||
69 | |||
70 | SetLastError(lasterr); | ||
71 | return buf; | ||
72 | } | ||
73 | |||
74 | #endif /* UNDER_CE && NO_ERRNO_H */ | ||
75 | |||
76 | /* Reset gzip file state */ | ||
77 | local void gz_reset(state) | ||
78 | gz_statep state; | ||
79 | { | ||
80 | state->how = 0; /* look for gzip header */ | ||
81 | if (state->mode == GZ_READ) { /* for reading ... */ | ||
82 | state->have = 0; /* no output data available */ | ||
83 | state->eof = 0; /* not at end of file */ | ||
84 | } | ||
85 | state->seek = 0; /* no seek request pending */ | ||
86 | gz_error(state, Z_OK, NULL); /* clear error */ | ||
87 | state->pos = 0; /* no uncompressed data yet */ | ||
88 | state->strm.avail_in = 0; /* no input data yet */ | ||
89 | } | ||
90 | |||
91 | /* Open a gzip file either by name or file descriptor. */ | ||
92 | local gzFile gz_open(path, fd, mode, use64) | ||
93 | const char *path; | ||
94 | int fd; | ||
95 | const char *mode; | ||
96 | int use64; | ||
97 | { | ||
98 | gz_statep state; | ||
99 | |||
100 | /* allocate gzFile structure to return */ | ||
101 | state = malloc(sizeof(gz_state)); | ||
102 | if (state == NULL) | ||
103 | return NULL; | ||
104 | state->size = 0; /* no buffers allocated yet */ | ||
105 | state->want = GZBUFSIZE; /* requested buffer size */ | ||
106 | state->msg = NULL; /* no error message yet */ | ||
107 | |||
108 | /* interpret mode */ | ||
109 | state->mode = GZ_NONE; | ||
110 | state->level = Z_DEFAULT_COMPRESSION; | ||
111 | state->strategy = Z_DEFAULT_STRATEGY; | ||
112 | while (*mode) { | ||
113 | if (*mode >= '0' && *mode <= '9') | ||
114 | state->level = *mode - '0'; | ||
115 | else | ||
116 | switch (*mode) { | ||
117 | case 'r': | ||
118 | state->mode = GZ_READ; | ||
119 | break; | ||
120 | #ifndef NO_GZCOMPRESS | ||
121 | case 'w': | ||
122 | state->mode = GZ_WRITE; | ||
123 | break; | ||
124 | case 'a': | ||
125 | state->mode = GZ_APPEND; | ||
126 | break; | ||
127 | #endif | ||
128 | case '+': /* can't read and write at the same time */ | ||
129 | free(state); | ||
130 | return NULL; | ||
131 | case 'b': /* ignore -- will request binary anyway */ | ||
132 | break; | ||
133 | case 'f': | ||
134 | state->strategy = Z_FILTERED; | ||
135 | break; | ||
136 | case 'h': | ||
137 | state->strategy = Z_HUFFMAN_ONLY; | ||
138 | break; | ||
139 | case 'R': | ||
140 | state->strategy = Z_RLE; | ||
141 | break; | ||
142 | case 'F': | ||
143 | state->strategy = Z_FIXED; | ||
144 | default: /* could consider as an error, but just ignore */ | ||
145 | ; | ||
146 | } | ||
147 | mode++; | ||
148 | } | ||
149 | |||
150 | /* must provide an "r", "w", or "a" */ | ||
151 | if (state->mode == GZ_NONE) { | ||
152 | free(state); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | /* open the file with the appropriate mode (or just use fd) */ | ||
157 | state->fd = fd != -1 ? fd : | ||
158 | open(path, | ||
159 | #ifdef O_LARGEFILE | ||
160 | (use64 ? O_LARGEFILE : 0) | | ||
161 | #endif | ||
162 | #ifdef O_BINARY | ||
163 | O_BINARY | | ||
164 | #endif | ||
165 | (state->mode == GZ_READ ? | ||
166 | O_RDONLY : | ||
167 | (O_WRONLY | O_CREAT | ( | ||
168 | state->mode == GZ_WRITE ? | ||
169 | O_TRUNC : | ||
170 | O_APPEND))), | ||
171 | 0666); | ||
172 | if (state->fd == -1) { | ||
173 | free(state); | ||
174 | return NULL; | ||
175 | } | ||
176 | if (state->mode == GZ_APPEND) | ||
177 | state->mode = GZ_WRITE; /* simplify later checks */ | ||
178 | |||
179 | /* save the path name for error messages */ | ||
180 | state->path = malloc(strlen(path) + 1); | ||
181 | strcpy(state->path, path); | ||
182 | |||
183 | /* save the current position for rewinding (only if reading) */ | ||
184 | if (state->mode == GZ_READ) { | ||
185 | state->start = LSEEK(state->fd, 0, SEEK_CUR); | ||
186 | if (state->start == -1) state->start = 0; | ||
187 | } | ||
188 | |||
189 | /* initialize stream */ | ||
190 | gz_reset(state); | ||
191 | |||
192 | /* return stream */ | ||
193 | return (gzFile)state; | ||
194 | } | ||
195 | |||
196 | /* -- see zlib.h -- */ | ||
197 | gzFile ZEXPORT gzopen(path, mode) | ||
198 | const char *path; | ||
199 | const char *mode; | ||
200 | { | ||
201 | return gz_open(path, -1, mode, 0); | ||
202 | } | ||
203 | |||
204 | /* -- see zlib.h -- */ | ||
205 | gzFile ZEXPORT gzopen64(path, mode) | ||
206 | const char *path; | ||
207 | const char *mode; | ||
208 | { | ||
209 | return gz_open(path, -1, mode, 1); | ||
210 | } | ||
211 | |||
212 | /* -- see zlib.h -- */ | ||
213 | gzFile ZEXPORT gzdopen(fd, mode) | ||
214 | int fd; | ||
215 | const char *mode; | ||
216 | { | ||
217 | char path[46]; /* allow up to 128-bit integers, so don't worry -- | ||
218 | the sprintf() is safe */ | ||
219 | |||
220 | if (fd < 0) | ||
221 | return NULL; | ||
222 | sprintf(path, "<fd:%d>", fd); /* for error messages */ | ||
223 | return gz_open(path, fd, mode, 1); | ||
224 | } | ||
225 | |||
226 | /* -- see zlib.h -- */ | ||
227 | int ZEXPORT gzbuffer(file, size) | ||
228 | gzFile file; | ||
229 | unsigned size; | ||
230 | { | ||
231 | gz_statep state; | ||
232 | |||
233 | /* get internal structure and check integrity */ | ||
234 | if (file == NULL) | ||
235 | return -1; | ||
236 | state = (gz_statep)file; | ||
237 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) | ||
238 | return -1; | ||
239 | |||
240 | /* make sure we haven't already allocated memory */ | ||
241 | if (state->size != 0) | ||
242 | return -1; | ||
243 | |||
244 | /* check and set requested size */ | ||
245 | if (size == 0) | ||
246 | return -1; | ||
247 | state->want = size; | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | /* -- see zlib.h -- */ | ||
252 | int ZEXPORT gzrewind(file) | ||
253 | gzFile file; | ||
254 | { | ||
255 | gz_statep state; | ||
256 | |||
257 | /* get internal structure */ | ||
258 | if (file == NULL) | ||
259 | return -1; | ||
260 | state = (gz_statep)file; | ||
261 | |||
262 | /* check that we're reading and that there's no error */ | ||
263 | if (state->mode != GZ_READ || state->err != Z_OK) | ||
264 | return -1; | ||
265 | |||
266 | /* back up and start over */ | ||
267 | if (LSEEK(state->fd, state->start, SEEK_SET) == -1) | ||
268 | return -1; | ||
269 | gz_reset(state); | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | /* -- see zlib.h -- */ | ||
274 | z_off64_t ZEXPORT gzseek64(file, offset, whence) | ||
275 | gzFile file; | ||
276 | z_off64_t offset; | ||
277 | int whence; | ||
278 | { | ||
279 | unsigned n; | ||
280 | z_off64_t ret; | ||
281 | gz_statep state; | ||
282 | |||
283 | /* get internal structure and check integrity */ | ||
284 | if (file == NULL) | ||
285 | return -1; | ||
286 | state = (gz_statep)file; | ||
287 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) | ||
288 | return -1; | ||
289 | |||
290 | /* check that there's no error */ | ||
291 | if (state->err != Z_OK) | ||
292 | return -1; | ||
293 | |||
294 | /* can only seek from start or relative to current position */ | ||
295 | if (whence != SEEK_SET && whence != SEEK_CUR) | ||
296 | return -1; | ||
297 | |||
298 | /* normalize offset to a SEEK_CUR specification */ | ||
299 | if (whence == SEEK_SET) | ||
300 | offset -= state->pos; | ||
301 | |||
302 | /* if within raw area while reading, just go there */ | ||
303 | if (state->mode == GZ_READ && state->how == 1 && | ||
304 | state->pos + offset >= state->raw) { | ||
305 | ret = LSEEK(state->fd, offset, SEEK_CUR); | ||
306 | if (ret == -1) | ||
307 | return -1; | ||
308 | state->have = 0; | ||
309 | state->eof = 0; | ||
310 | state->seek = 0; | ||
311 | gz_error(state, Z_OK, NULL); | ||
312 | state->strm.avail_in = 0; | ||
313 | state->pos += offset; | ||
314 | return state->pos; | ||
315 | } | ||
316 | |||
317 | /* calculate skip amount, rewinding if needed for back seek when reading */ | ||
318 | if (offset < 0) { | ||
319 | if (state->mode != GZ_READ) /* writing -- can't go backwards */ | ||
320 | return -1; | ||
321 | offset += state->pos; | ||
322 | if (offset < 0) /* before start of file! */ | ||
323 | return -1; | ||
324 | if (gzrewind(file) == -1) /* rewind, then skip to offset */ | ||
325 | return -1; | ||
326 | } | ||
327 | |||
328 | /* if reading, skip what's in output buffer (one less gz_getc() check) */ | ||
329 | if (state->mode == GZ_READ) { | ||
330 | n = state->have > offset ? (unsigned)offset : state->have; | ||
331 | state->have -= n; | ||
332 | state->next += n; | ||
333 | state->pos += n; | ||
334 | offset -= n; | ||
335 | } | ||
336 | |||
337 | /* request skip (if not zero) */ | ||
338 | if (offset) { | ||
339 | state->seek = 1; | ||
340 | state->skip = offset; | ||
341 | } | ||
342 | return state->pos + offset; | ||
343 | } | ||
344 | |||
345 | /* -- see zlib.h -- */ | ||
346 | z_off_t ZEXPORT gzseek(file, offset, whence) | ||
347 | gzFile file; | ||
348 | z_off_t offset; | ||
349 | int whence; | ||
350 | { | ||
351 | z_off64_t ret; | ||
352 | |||
353 | ret = gzseek64(file, (z_off64_t)offset, whence); | ||
354 | return ret == (z_off_t)ret ? (z_off_t)ret : -1; | ||
355 | } | ||
356 | |||
357 | /* -- see zlib.h -- */ | ||
358 | z_off64_t ZEXPORT gztell64(file) | ||
359 | gzFile file; | ||
360 | { | ||
361 | gz_statep state; | ||
362 | |||
363 | /* get internal structure and check integrity */ | ||
364 | if (file == NULL) | ||
365 | return -1; | ||
366 | state = (gz_statep)file; | ||
367 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) | ||
368 | return -1; | ||
369 | |||
370 | /* return position */ | ||
371 | return state->pos + (state->seek ? state->skip : 0); | ||
372 | } | ||
373 | |||
374 | /* -- see zlib.h -- */ | ||
375 | z_off_t ZEXPORT gztell(file) | ||
376 | gzFile file; | ||
377 | { | ||
378 | z_off64_t ret; | ||
379 | |||
380 | ret = gztell64(file); | ||
381 | return ret == (z_off_t)ret ? (z_off_t)ret : -1; | ||
382 | } | ||
383 | |||
384 | /* -- see zlib.h -- */ | ||
385 | z_off64_t ZEXPORT gzoffset64(file) | ||
386 | gzFile file; | ||
387 | { | ||
388 | z_off64_t offset; | ||
389 | gz_statep state; | ||
390 | |||
391 | /* get internal structure and check integrity */ | ||
392 | if (file == NULL) | ||
393 | return -1; | ||
394 | state = (gz_statep)file; | ||
395 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) | ||
396 | return -1; | ||
397 | |||
398 | /* compute and return effective offset in file */ | ||
399 | offset = LSEEK(state->fd, 0, SEEK_CUR); | ||
400 | if (offset == -1) | ||
401 | return -1; | ||
402 | if (state->mode == GZ_READ) /* reading */ | ||
403 | offset -= state->strm.avail_in; /* don't count buffered input */ | ||
404 | return offset; | ||
405 | } | ||
406 | |||
407 | /* -- see zlib.h -- */ | ||
408 | z_off_t ZEXPORT gzoffset(file) | ||
409 | gzFile file; | ||
410 | { | ||
411 | z_off64_t ret; | ||
412 | |||
413 | ret = gzoffset64(file); | ||
414 | return ret == (z_off_t)ret ? (z_off_t)ret : -1; | ||
415 | } | ||
416 | |||
417 | /* -- see zlib.h -- */ | ||
418 | int ZEXPORT gzeof(file) | ||
419 | gzFile file; | ||
420 | { | ||
421 | gz_statep state; | ||
422 | |||
423 | /* get internal structure and check integrity */ | ||
424 | if (file == NULL) | ||
425 | return -1; | ||
426 | state = (gz_statep)file; | ||
427 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) | ||
428 | return -1; | ||
429 | |||
430 | /* return end-of-file state */ | ||
431 | return state->mode == GZ_READ ? (state->eof && state->have == 0) : 0; | ||
432 | } | ||
433 | |||
434 | /* -- see zlib.h -- */ | ||
435 | const char * ZEXPORT gzerror(file, errnum) | ||
436 | gzFile file; | ||
437 | int *errnum; | ||
438 | { | ||
439 | gz_statep state; | ||
440 | |||
441 | /* get internal structure and check integrity */ | ||
442 | if (file == NULL) | ||
443 | return NULL; | ||
444 | state = (gz_statep)file; | ||
445 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) | ||
446 | return NULL; | ||
447 | |||
448 | /* return error information */ | ||
449 | *errnum = state->err; | ||
450 | return state->msg == NULL ? "" : state->msg; | ||
451 | } | ||
452 | |||
453 | /* -- see zlib.h -- */ | ||
454 | void ZEXPORT gzclearerr(file) | ||
455 | gzFile file; | ||
456 | { | ||
457 | gz_statep state; | ||
458 | |||
459 | /* get internal structure and check integrity */ | ||
460 | if (file == NULL) | ||
461 | return; | ||
462 | state = (gz_statep)file; | ||
463 | if (state->mode != GZ_READ && state->mode != GZ_WRITE) | ||
464 | return; | ||
465 | |||
466 | /* clear error and end-of-file */ | ||
467 | if (state->mode == GZ_READ) | ||
468 | state->eof = 0; | ||
469 | gz_error(state, Z_OK, NULL); | ||
470 | } | ||
471 | |||
472 | /* Create an error message in allocated memory and set state->err and | ||
473 | state->msg accordingly. Free any previous error message already there. Do | ||
474 | not try to free or allocate space if the error is Z_MEM_ERROR (out of | ||
475 | memory). Simply save the error message as a static string. If there is | ||
476 | an allocation failure constructing the error message, then convert the | ||
477 | error to out of memory. */ | ||
478 | void ZEXPORT gz_error(state, err, msg) | ||
479 | gz_statep state; | ||
480 | int err; | ||
481 | char *msg; | ||
482 | { | ||
483 | /* free previously allocated message and clear */ | ||
484 | if (state->msg != NULL) { | ||
485 | if (state->err != Z_MEM_ERROR) | ||
486 | free(state->msg); | ||
487 | state->msg = NULL; | ||
488 | } | ||
489 | |||
490 | /* set error code, and if no message, then done */ | ||
491 | state->err = err; | ||
492 | if (msg == NULL) | ||
493 | return; | ||
494 | |||
495 | /* for an out of memory error, save as static string */ | ||
496 | if (err == Z_MEM_ERROR) { | ||
497 | state->msg = msg; | ||
498 | return; | ||
499 | } | ||
500 | |||
501 | /* construct error message with path */ | ||
502 | if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { | ||
503 | state->err = Z_MEM_ERROR; | ||
504 | state->msg = "out of memory"; | ||
505 | return; | ||
506 | } | ||
507 | strcpy(state->msg, state->path); | ||
508 | strcat(state->msg, ": "); | ||
509 | strcat(state->msg, msg); | ||
510 | return; | ||
511 | } | ||
512 | |||
513 | #endif /* !OLD_GZIO */ | ||