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