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