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