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