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