xref: /titanic_52/usr/src/boot/lib/libz/gzlib.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
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. */
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 */
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. */
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 -- */
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 -- */
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 -- */
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
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 -- */
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 -- */
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 -- */
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 -- */
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 -- */
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 -- */
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 -- */
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 -- */
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 -- */
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 -- */
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 -- */
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. */
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 */
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