1 /* gzlib.c -- zlib functions common to reading and writing gzip files
2 * Copyright (C) 2004, 2010, 2011, 2012 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. */
gz_strwinerror(error)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 */
gz_reset(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. */
gz_open(path,fd,mode)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 = 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 case 'T':
166 state->direct = 1;
167 default: /* could consider as an error, but just ignore */
168 ;
169 }
170 mode++;
171 }
172
173 /* must provide an "r", "w", or "a" */
174 if (state->mode == GZ_NONE) {
175 free(state);
176 return NULL;
177 }
178
179 /* can't force transparent read */
180 if (state->mode == GZ_READ) {
181 if (state->direct) {
182 free(state);
183 return NULL;
184 }
185 state->direct = 1; /* for empty file */
186 }
187
188 /* save the path name for error messages */
189 #ifdef _WIN32
190 if (fd == -2) {
191 len = wcstombs(NULL, path, 0);
192 if (len == (size_t)-1)
193 len = 0;
194 }
195 else
196 #endif
197 len = strlen(path);
198 state->path = malloc(len + 1);
199 if (state->path == NULL) {
200 free(state);
201 return NULL;
202 }
203 #ifdef _WIN32
204 if (fd == -2)
205 if (len)
206 wcstombs(state->path, path, len + 1);
207 else
208 *(state->path) = 0;
209 else
210 #endif
211 strcpy(state->path, path);
212
213 /* compute the flags for open() */
214 oflag =
215 #ifdef O_LARGEFILE
216 O_LARGEFILE |
217 #endif
218 #ifdef O_BINARY
219 O_BINARY |
220 #endif
221 #ifdef O_CLOEXEC
222 (cloexec ? O_CLOEXEC : 0) |
223 #endif
224 (state->mode == GZ_READ ?
225 O_RDONLY :
226 (O_WRONLY | O_CREAT |
227 #ifdef O_EXCL
228 (exclusive ? O_EXCL : 0) |
229 #endif
230 (state->mode == GZ_WRITE ?
231 O_TRUNC :
232 O_APPEND)));
233
234 /* open the file with the appropriate flags (or just use fd) */
235 state->fd = fd > -1 ? fd : (
236 #ifdef _WIN32
237 fd == -2 ? _wopen(path, oflag, 0666) :
238 #endif
239 open(path, oflag, 0666));
240 if (state->fd == -1) {
241 free(state->path);
242 free(state);
243 return NULL;
244 }
245 if (state->mode == GZ_APPEND)
246 state->mode = GZ_WRITE; /* simplify later checks */
247
248 /* save the current position for rewinding (only if reading) */
249 if (state->mode == GZ_READ) {
250 state->start = LSEEK(state->fd, 0, SEEK_CUR);
251 if (state->start == -1) state->start = 0;
252 }
253
254 /* initialize stream */
255 gz_reset(state);
256
257 /* return stream */
258 return (gzFile)state;
259 }
260
261 /* -- see zlib.h -- */
gzopen(path,mode)262 gzFile ZEXPORT gzopen(path, mode)
263 const char *path;
264 const char *mode;
265 {
266 return gz_open(path, -1, mode);
267 }
268
269 /* -- see zlib.h -- */
gzopen64(path,mode)270 gzFile ZEXPORT gzopen64(path, mode)
271 const char *path;
272 const char *mode;
273 {
274 return gz_open(path, -1, mode);
275 }
276
277 /* -- see zlib.h -- */
gzdopen(fd,mode)278 gzFile ZEXPORT gzdopen(fd, mode)
279 int fd;
280 const char *mode;
281 {
282 char *path; /* identifier for error messages */
283 gzFile gz;
284
285 if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL)
286 return NULL;
287 sprintf(path, "<fd:%d>", fd); /* for debugging */
288 gz = gz_open(path, fd, mode);
289 free(path);
290 return gz;
291 }
292
293 /* -- see zlib.h -- */
294 #ifdef _WIN32
gzopen_w(path,mode)295 gzFile ZEXPORT gzopen_w(path, mode)
296 const wchar_t *path;
297 const char *mode;
298 {
299 return gz_open(path, -2, mode);
300 }
301 #endif
302
303 /* -- see zlib.h -- */
gzbuffer(file,size)304 int ZEXPORT gzbuffer(file, size)
305 gzFile file;
306 unsigned size;
307 {
308 gz_statep state;
309
310 /* get internal structure and check integrity */
311 if (file == NULL)
312 return -1;
313 state = (gz_statep)file;
314 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
315 return -1;
316
317 /* make sure we haven't already allocated memory */
318 if (state->size != 0)
319 return -1;
320
321 /* check and set requested size */
322 if (size < 2)
323 size = 2; /* need two bytes to check magic header */
324 state->want = size;
325 return 0;
326 }
327
328 /* -- see zlib.h -- */
gzrewind(file)329 int ZEXPORT gzrewind(file)
330 gzFile file;
331 {
332 gz_statep state;
333
334 /* get internal structure */
335 if (file == NULL)
336 return -1;
337 state = (gz_statep)file;
338
339 /* check that we're reading and that there's no error */
340 if (state->mode != GZ_READ ||
341 (state->err != Z_OK && state->err != Z_BUF_ERROR))
342 return -1;
343
344 /* back up and start over */
345 if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
346 return -1;
347 gz_reset(state);
348 return 0;
349 }
350
351 /* -- see zlib.h -- */
gzseek64(file,offset,whence)352 z_off64_t ZEXPORT gzseek64(file, offset, whence)
353 gzFile file;
354 z_off64_t offset;
355 int whence;
356 {
357 unsigned n;
358 z_off64_t ret;
359 gz_statep state;
360
361 /* get internal structure and check integrity */
362 if (file == NULL)
363 return -1;
364 state = (gz_statep)file;
365 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
366 return -1;
367
368 /* check that there's no error */
369 if (state->err != Z_OK && state->err != Z_BUF_ERROR)
370 return -1;
371
372 /* can only seek from start or relative to current position */
373 if (whence != SEEK_SET && whence != SEEK_CUR)
374 return -1;
375
376 /* normalize offset to a SEEK_CUR specification */
377 if (whence == SEEK_SET)
378 offset -= state->x.pos;
379 else if (state->seek)
380 offset += state->skip;
381 state->seek = 0;
382
383 /* if within raw area while reading, just go there */
384 if (state->mode == GZ_READ && state->how == COPY &&
385 state->x.pos + offset >= 0) {
386 ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
387 if (ret == -1)
388 return -1;
389 state->x.have = 0;
390 state->eof = 0;
391 state->past = 0;
392 state->seek = 0;
393 gz_error(state, Z_OK, NULL);
394 state->strm.avail_in = 0;
395 state->x.pos += offset;
396 return state->x.pos;
397 }
398
399 /* calculate skip amount, rewinding if needed for back seek when reading */
400 if (offset < 0) {
401 if (state->mode != GZ_READ) /* writing -- can't go backwards */
402 return -1;
403 offset += state->x.pos;
404 if (offset < 0) /* before start of file! */
405 return -1;
406 if (gzrewind(file) == -1) /* rewind, then skip to offset */
407 return -1;
408 }
409
410 /* if reading, skip what's in output buffer (one less gzgetc() check) */
411 if (state->mode == GZ_READ) {
412 n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
413 (unsigned)offset : state->x.have;
414 state->x.have -= n;
415 state->x.next += n;
416 state->x.pos += n;
417 offset -= n;
418 }
419
420 /* request skip (if not zero) */
421 if (offset) {
422 state->seek = 1;
423 state->skip = offset;
424 }
425 return state->x.pos + offset;
426 }
427
428 /* -- see zlib.h -- */
gzseek(file,offset,whence)429 z_off_t ZEXPORT gzseek(file, offset, whence)
430 gzFile file;
431 z_off_t offset;
432 int whence;
433 {
434 z_off64_t ret;
435
436 ret = gzseek64(file, (z_off64_t)offset, whence);
437 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
438 }
439
440 /* -- see zlib.h -- */
gztell64(file)441 z_off64_t ZEXPORT gztell64(file)
442 gzFile file;
443 {
444 gz_statep state;
445
446 /* get internal structure and check integrity */
447 if (file == NULL)
448 return -1;
449 state = (gz_statep)file;
450 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
451 return -1;
452
453 /* return position */
454 return state->x.pos + (state->seek ? state->skip : 0);
455 }
456
457 /* -- see zlib.h -- */
gztell(file)458 z_off_t ZEXPORT gztell(file)
459 gzFile file;
460 {
461 z_off64_t ret;
462
463 ret = gztell64(file);
464 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
465 }
466
467 /* -- see zlib.h -- */
gzoffset64(file)468 z_off64_t ZEXPORT gzoffset64(file)
469 gzFile file;
470 {
471 z_off64_t offset;
472 gz_statep state;
473
474 /* get internal structure and check integrity */
475 if (file == NULL)
476 return -1;
477 state = (gz_statep)file;
478 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
479 return -1;
480
481 /* compute and return effective offset in file */
482 offset = LSEEK(state->fd, 0, SEEK_CUR);
483 if (offset == -1)
484 return -1;
485 if (state->mode == GZ_READ) /* reading */
486 offset -= state->strm.avail_in; /* don't count buffered input */
487 return offset;
488 }
489
490 /* -- see zlib.h -- */
gzoffset(file)491 z_off_t ZEXPORT gzoffset(file)
492 gzFile file;
493 {
494 z_off64_t ret;
495
496 ret = gzoffset64(file);
497 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
498 }
499
500 /* -- see zlib.h -- */
gzeof(file)501 int ZEXPORT gzeof(file)
502 gzFile file;
503 {
504 gz_statep state;
505
506 /* get internal structure and check integrity */
507 if (file == NULL)
508 return 0;
509 state = (gz_statep)file;
510 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
511 return 0;
512
513 /* return end-of-file state */
514 return state->mode == GZ_READ ? state->past : 0;
515 }
516
517 /* -- see zlib.h -- */
gzerror(file,errnum)518 const char * ZEXPORT gzerror(file, errnum)
519 gzFile file;
520 int *errnum;
521 {
522 gz_statep state;
523
524 /* get internal structure and check integrity */
525 if (file == NULL)
526 return NULL;
527 state = (gz_statep)file;
528 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
529 return NULL;
530
531 /* return error information */
532 if (errnum != NULL)
533 *errnum = state->err;
534 return state->msg == NULL ? "" : state->msg;
535 }
536
537 /* -- see zlib.h -- */
gzclearerr(file)538 void ZEXPORT gzclearerr(file)
539 gzFile file;
540 {
541 gz_statep state;
542
543 /* get internal structure and check integrity */
544 if (file == NULL)
545 return;
546 state = (gz_statep)file;
547 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
548 return;
549
550 /* clear error and end-of-file */
551 if (state->mode == GZ_READ) {
552 state->eof = 0;
553 state->past = 0;
554 }
555 gz_error(state, Z_OK, NULL);
556 }
557
558 /* Create an error message in allocated memory and set state->err and
559 state->msg accordingly. Free any previous error message already there. Do
560 not try to free or allocate space if the error is Z_MEM_ERROR (out of
561 memory). Simply save the error message as a static string. If there is an
562 allocation failure constructing the error message, then convert the error to
563 out of memory. */
gz_error(state,err,msg)564 void ZLIB_INTERNAL gz_error(state, err, msg)
565 gz_statep state;
566 int err;
567 const char *msg;
568 {
569 /* free previously allocated message and clear */
570 if (state->msg != NULL) {
571 if (state->err != Z_MEM_ERROR)
572 free(state->msg);
573 state->msg = NULL;
574 }
575
576 /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
577 if (err != Z_OK && err != Z_BUF_ERROR)
578 state->x.have = 0;
579
580 /* set error code, and if no message, then done */
581 state->err = err;
582 if (msg == NULL)
583 return;
584
585 /* for an out of memory error, save as static string */
586 if (err == Z_MEM_ERROR) {
587 state->msg = (char *)msg;
588 return;
589 }
590
591 /* construct error message with path */
592 if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
593 state->err = Z_MEM_ERROR;
594 state->msg = (char *)"out of memory";
595 return;
596 }
597 strcpy(state->msg, state->path);
598 strcat(state->msg, ": ");
599 strcat(state->msg, msg);
600 return;
601 }
602
603 #ifndef INT_MAX
604 /* portably return maximum value for an int (when limits.h presumed not
605 available) -- we need to do this to cover cases where 2's complement not
606 used, since C standard permits 1's complement and sign-bit representations,
607 otherwise we could just use ((unsigned)-1) >> 1 */
gz_intmax()608 unsigned ZLIB_INTERNAL gz_intmax()
609 {
610 unsigned p, q;
611
612 p = 1;
613 do {
614 q = p;
615 p <<= 1;
616 p++;
617 } while (p > q);
618 return q >> 1;
619 }
620 #endif
621