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