1/* gzlib.c -- zlib functions common to reading and writing gzip files
2 * Copyright (C) 2004-2017 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__) && !defined(__MINGW32__)
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 */
19local void gz_reset OF((gz_statep));
20local 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. */
33char 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 */
75local 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. */
91local gzFile gz_open(path, fd, mode)
92 const void *path;
93 int fd;
94 const char *mode;
95{
96 gz_statep state;
97 z_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 WIDECHAR
192 if (fd == -2) {
193 len = wcstombs(NULL, path, 0);
194 if (len == (z_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 WIDECHAR
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 (void)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 WIDECHAR
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 LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */
253 state->mode = GZ_WRITE; /* simplify later checks */
254 }
255
256 /* save the current position for rewinding (only if reading) */
257 if (state->mode == GZ_READ) {
258 state->start = LSEEK(state->fd, 0, SEEK_CUR);
259 if (state->start == -1) state->start = 0;
260 }
261
262 /* initialize stream */
263 gz_reset(state);
264
265 /* return stream */
266 return (gzFile)state;
267}
268
269/* -- see zlib.h -- */
270gzFile ZEXPORT gzopen(path, mode)
271 const char *path;
272 const char *mode;
273{
274 return gz_open(path, -1, mode);
275}
276
277/* -- see zlib.h -- */
278gzFile ZEXPORT gzopen64(path, mode)
279 const char *path;
280 const char *mode;
281{
282 return gz_open(path, -1, mode);
283}
284
285/* -- see zlib.h -- */
286gzFile ZEXPORT gzdopen(fd, mode)
287 int fd;
288 const char *mode;
289{
290 char *path; /* identifier for error messages */
291 gzFile gz;
292
293 if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
294 return NULL;
295#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
296 (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
297#else
298 sprintf(path, "<fd:%d>", fd); /* for debugging */
299#endif
300 gz = gz_open(path, fd, mode);
301 free(path);
302 return gz;
303}
304
305/* -- see zlib.h -- */
306#ifdef WIDECHAR
307gzFile ZEXPORT gzopen_w(path, mode)
308 const wchar_t *path;
309 const char *mode;
310{
311 return gz_open(path, -2, mode);
312}
313#endif
314
315/* -- see zlib.h -- */
316int ZEXPORT gzbuffer(file, size)
317 gzFile file;
318 unsigned size;
319{
320 gz_statep state;
321
322 /* get internal structure and check integrity */
323 if (file == NULL)
324 return -1;
325 state = (gz_statep)file;
326 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
327 return -1;
328
329 /* make sure we haven't already allocated memory */
330 if (state->size != 0)
331 return -1;
332
333 /* check and set requested size */
334 if ((size << 1) < size)
335 return -1; /* need to be able to double it */
336 if (size < 2)
337 size = 2; /* need two bytes to check magic header */
338 state->want = size;
339 return 0;
340}
341
342/* -- see zlib.h -- */
343int ZEXPORT gzrewind(file)
344 gzFile file;
345{
346 gz_statep state;
347
348 /* get internal structure */
349 if (file == NULL)
350 return -1;
351 state = (gz_statep)file;
352
353 /* check that we're reading and that there's no error */
354 if (state->mode != GZ_READ ||
355 (state->err != Z_OK && state->err != Z_BUF_ERROR))
356 return -1;
357
358 /* back up and start over */
359 if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
360 return -1;
361 gz_reset(state);
362 return 0;
363}
364
365/* -- see zlib.h -- */
366z_off64_t ZEXPORT gzseek64(file, offset, whence)
367 gzFile file;
368 z_off64_t offset;
369 int whence;
370{
371 unsigned n;
372 z_off64_t ret;
373 gz_statep state;
374
375 /* get internal structure and check integrity */
376 if (file == NULL)
377 return -1;
378 state = (gz_statep)file;
379 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
380 return -1;
381
382 /* check that there's no error */
383 if (state->err != Z_OK && state->err != Z_BUF_ERROR)
384 return -1;
385
386 /* can only seek from start or relative to current position */
387 if (whence != SEEK_SET && whence != SEEK_CUR)
388 return -1;
389
390 /* normalize offset to a SEEK_CUR specification */
391 if (whence == SEEK_SET)
392 offset -= state->x.pos;
393 else if (state->seek)
394 offset += state->skip;
395 state->seek = 0;
396
397 /* if within raw area while reading, just go there */
398 if (state->mode == GZ_READ && state->how == COPY &&
399 state->x.pos + offset >= 0) {
400 ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
401 if (ret == -1)
402 return -1;
403 state->x.have = 0;
404 state->eof = 0;
405 state->past = 0;
406 state->seek = 0;
407 gz_error(state, Z_OK, NULL);
408 state->strm.avail_in = 0;
409 state->x.pos += offset;
410 return state->x.pos;
411 }
412
413 /* calculate skip amount, rewinding if needed for back seek when reading */
414 if (offset < 0) {
415 if (state->mode != GZ_READ) /* writing -- can't go backwards */
416 return -1;
417 offset += state->x.pos;
418 if (offset < 0) /* before start of file! */
419 return -1;
420 if (gzrewind(file) == -1) /* rewind, then skip to offset */
421 return -1;
422 }
423
424 /* if reading, skip what's in output buffer (one less gzgetc() check) */
425 if (state->mode == GZ_READ) {
426 n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
427 (unsigned)offset : state->x.have;
428 state->x.have -= n;
429 state->x.next += n;
430 state->x.pos += n;
431 offset -= n;
432 }
433
434 /* request skip (if not zero) */
435 if (offset) {
436 state->seek = 1;
437 state->skip = offset;
438 }
439 return state->x.pos + offset;
440}
441
442/* -- see zlib.h -- */
443z_off_t ZEXPORT gzseek(file, offset, whence)
444 gzFile file;
445 z_off_t offset;
446 int whence;
447{
448 z_off64_t ret;
449
450 ret = gzseek64(file, (z_off64_t)offset, whence);
451 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
452}
453
454/* -- see zlib.h -- */
455z_off64_t ZEXPORT gztell64(file)
456 gzFile file;
457{
458 gz_statep state;
459
460 /* get internal structure and check integrity */
461 if (file == NULL)
462 return -1;
463 state = (gz_statep)file;
464 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
465 return -1;
466
467 /* return position */
468 return state->x.pos + (state->seek ? state->skip : 0);
469}
470
471/* -- see zlib.h -- */
472z_off_t ZEXPORT gztell(file)
473 gzFile file;
474{
475 z_off64_t ret;
476
477 ret = gztell64(file);
478 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
479}
480
481/* -- see zlib.h -- */
482z_off64_t ZEXPORT gzoffset64(file)
483 gzFile file;
484{
485 z_off64_t offset;
486 gz_statep state;
487
488 /* get internal structure and check integrity */
489 if (file == NULL)
490 return -1;
491 state = (gz_statep)file;
492 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
493 return -1;
494
495 /* compute and return effective offset in file */
496 offset = LSEEK(state->fd, 0, SEEK_CUR);
497 if (offset == -1)
498 return -1;
499 if (state->mode == GZ_READ) /* reading */
500 offset -= state->strm.avail_in; /* don't count buffered input */
501 return offset;
502}
503
504/* -- see zlib.h -- */
505z_off_t ZEXPORT gzoffset(file)
506 gzFile file;
507{
508 z_off64_t ret;
509
510 ret = gzoffset64(file);
511 return ret == (z_off_t)ret ? (z_off_t)ret : -1;
512}
513
514/* -- see zlib.h -- */
515int ZEXPORT gzeof(file)
516 gzFile file;
517{
518 gz_statep state;
519
520 /* get internal structure and check integrity */
521 if (file == NULL)
522 return 0;
523 state = (gz_statep)file;
524 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
525 return 0;
526
527 /* return end-of-file state */
528 return state->mode == GZ_READ ? state->past : 0;
529}
530
531/* -- see zlib.h -- */
532const char * ZEXPORT gzerror(file, errnum)
533 gzFile file;
534 int *errnum;
535{
536 gz_statep state;
537
538 /* get internal structure and check integrity */
539 if (file == NULL)
540 return NULL;
541 state = (gz_statep)file;
542 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
543 return NULL;
544
545 /* return error information */
546 if (errnum != NULL)
547 *errnum = state->err;
548 return state->err == Z_MEM_ERROR ? "out of memory" :
549 (state->msg == NULL ? "" : state->msg);
550}
551
552/* -- see zlib.h -- */
553void ZEXPORT gzclearerr(file)
554 gzFile file;
555{
556 gz_statep state;
557
558 /* get internal structure and check integrity */
559 if (file == NULL)
560 return;
561 state = (gz_statep)file;
562 if (state->mode != GZ_READ && state->mode != GZ_WRITE)
563 return;
564
565 /* clear error and end-of-file */
566 if (state->mode == GZ_READ) {
567 state->eof = 0;
568 state->past = 0;
569 }
570 gz_error(state, Z_OK, NULL);
571}
572
573/* Create an error message in allocated memory and set state->err and
574 state->msg accordingly. Free any previous error message already there. Do
575 not try to free or allocate space if the error is Z_MEM_ERROR (out of
576 memory). Simply save the error message as a static string. If there is an
577 allocation failure constructing the error message, then convert the error to
578 out of memory. */
579void ZLIB_INTERNAL gz_error(state, err, msg)
580 gz_statep state;
581 int err;
582 const char *msg;
583{
584 /* free previously allocated message and clear */
585 if (state->msg != NULL) {
586 if (state->err != Z_MEM_ERROR)
587 free(state->msg);
588 state->msg = NULL;
589 }
590
591 /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
592 if (err != Z_OK && err != Z_BUF_ERROR)
593 state->x.have = 0;
594
595 /* set error code, and if no message, then done */
596 state->err = err;
597 if (msg == NULL)
598 return;
599
600 /* for an out of memory error, return literal string when requested */
601 if (err == Z_MEM_ERROR)
602 return;
603
604 /* construct error message with path */
605 if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
606 NULL) {
607 state->err = Z_MEM_ERROR;
608 return;
609 }
610#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
611 (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
612 "%s%s%s", state->path, ": ", msg);
613#else
614 strcpy(state->msg, state->path);
615 strcat(state->msg, ": ");
616 strcat(state->msg, msg);
617#endif
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 */
625unsigned 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