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