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