1205194Sdelphij/* gzlib.c -- zlib functions common to reading and writing gzip files
2254069Sdelphij * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler
3205194Sdelphij * For conditions of distribution and use, see copyright notice in zlib.h
4205194Sdelphij */
5205194Sdelphij
6206002Sdelphij/* $FreeBSD$ */
7206002Sdelphij
8205194Sdelphij#include "gzguts.h"
9206002Sdelphij#include "zutil.h"
10205194Sdelphij
11237691Sdelphij#if defined(_WIN32) && !defined(__BORLANDC__)
12237691Sdelphij#  define LSEEK _lseeki64
13237691Sdelphij#else
14206708Sdelphij#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
15205194Sdelphij#  define LSEEK lseek64
16205194Sdelphij#else
17205194Sdelphij#  define LSEEK lseek
18205194Sdelphij#endif
19237691Sdelphij#endif
20205194Sdelphij
21205194Sdelphij/* Local functions */
22205194Sdelphijlocal void gz_reset OF((gz_statep));
23237691Sdelphijlocal gzFile gz_open OF((const void *, int, const char *));
24205194Sdelphij
25206002Sdelphij#if defined UNDER_CE
26205194Sdelphij
27205194Sdelphij/* Map the Windows error number in ERROR to a locale-dependent error message
28205194Sdelphij   string and return a pointer to it.  Typically, the values for ERROR come
29205194Sdelphij   from GetLastError.
30205194Sdelphij
31205194Sdelphij   The string pointed to shall not be modified by the application, but may be
32205194Sdelphij   overwritten by a subsequent call to gz_strwinerror
33205194Sdelphij
34205194Sdelphij   The gz_strwinerror function does not change the current setting of
35205194Sdelphij   GetLastError. */
36206924Sdelphijchar ZLIB_INTERNAL *gz_strwinerror (error)
37205194Sdelphij     DWORD error;
38205194Sdelphij{
39205194Sdelphij    static char buf[1024];
40205194Sdelphij
41205194Sdelphij    wchar_t *msgbuf;
42205194Sdelphij    DWORD lasterr = GetLastError();
43205194Sdelphij    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
44205194Sdelphij        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
45205194Sdelphij        NULL,
46205194Sdelphij        error,
47205194Sdelphij        0, /* Default language */
48205194Sdelphij        (LPVOID)&msgbuf,
49205194Sdelphij        0,
50205194Sdelphij        NULL);
51205194Sdelphij    if (chars != 0) {
52205194Sdelphij        /* If there is an \r\n appended, zap it.  */
53205194Sdelphij        if (chars >= 2
54205194Sdelphij            && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
55205194Sdelphij            chars -= 2;
56205194Sdelphij            msgbuf[chars] = 0;
57205194Sdelphij        }
58205194Sdelphij
59205194Sdelphij        if (chars > sizeof (buf) - 1) {
60205194Sdelphij            chars = sizeof (buf) - 1;
61205194Sdelphij            msgbuf[chars] = 0;
62205194Sdelphij        }
63205194Sdelphij
64205194Sdelphij        wcstombs(buf, msgbuf, chars + 1);
65205194Sdelphij        LocalFree(msgbuf);
66205194Sdelphij    }
67205194Sdelphij    else {
68205194Sdelphij        sprintf(buf, "unknown win32 error (%ld)", error);
69205194Sdelphij    }
70205194Sdelphij
71205194Sdelphij    SetLastError(lasterr);
72205194Sdelphij    return buf;
73205194Sdelphij}
74205194Sdelphij
75206002Sdelphij#endif /* UNDER_CE */
76205194Sdelphij
77205194Sdelphij/* Reset gzip file state */
78205194Sdelphijlocal void gz_reset(state)
79205194Sdelphij    gz_statep state;
80205194Sdelphij{
81237691Sdelphij    state->x.have = 0;              /* no output data available */
82205194Sdelphij    if (state->mode == GZ_READ) {   /* for reading ... */
83205194Sdelphij        state->eof = 0;             /* not at end of file */
84237691Sdelphij        state->past = 0;            /* have not read past end yet */
85205194Sdelphij        state->how = LOOK;          /* look for gzip header */
86205194Sdelphij    }
87205194Sdelphij    state->seek = 0;                /* no seek request pending */
88205194Sdelphij    gz_error(state, Z_OK, NULL);    /* clear error */
89237691Sdelphij    state->x.pos = 0;               /* no uncompressed data yet */
90205194Sdelphij    state->strm.avail_in = 0;       /* no input data yet */
91205194Sdelphij}
92205194Sdelphij
93205194Sdelphij/* Open a gzip file either by name or file descriptor. */
94205194Sdelphijlocal gzFile gz_open(path, fd, mode)
95237691Sdelphij    const void *path;
96205194Sdelphij    int fd;
97205194Sdelphij    const char *mode;
98205194Sdelphij{
99205194Sdelphij    gz_statep state;
100237691Sdelphij    size_t len;
101237691Sdelphij    int oflag;
102237691Sdelphij#ifdef O_CLOEXEC
103237691Sdelphij    int cloexec = 0;
104237691Sdelphij#endif
105237691Sdelphij#ifdef O_EXCL
106237691Sdelphij    int exclusive = 0;
107237691Sdelphij#endif
108205194Sdelphij
109237691Sdelphij    /* check input */
110237691Sdelphij    if (path == NULL)
111237691Sdelphij        return NULL;
112237691Sdelphij
113205194Sdelphij    /* allocate gzFile structure to return */
114254069Sdelphij    state = (gz_statep)malloc(sizeof(gz_state));
115205194Sdelphij    if (state == NULL)
116205194Sdelphij        return NULL;
117205194Sdelphij    state->size = 0;            /* no buffers allocated yet */
118205194Sdelphij    state->want = GZBUFSIZE;    /* requested buffer size */
119205194Sdelphij    state->msg = NULL;          /* no error message yet */
120205194Sdelphij
121205194Sdelphij    /* interpret mode */
122205194Sdelphij    state->mode = GZ_NONE;
123205194Sdelphij    state->level = Z_DEFAULT_COMPRESSION;
124205194Sdelphij    state->strategy = Z_DEFAULT_STRATEGY;
125237691Sdelphij    state->direct = 0;
126205194Sdelphij    while (*mode) {
127205194Sdelphij        if (*mode >= '0' && *mode <= '9')
128205194Sdelphij            state->level = *mode - '0';
129205194Sdelphij        else
130205194Sdelphij            switch (*mode) {
131205194Sdelphij            case 'r':
132205194Sdelphij                state->mode = GZ_READ;
133205194Sdelphij                break;
134205194Sdelphij#ifndef NO_GZCOMPRESS
135205194Sdelphij            case 'w':
136205194Sdelphij                state->mode = GZ_WRITE;
137205194Sdelphij                break;
138205194Sdelphij            case 'a':
139205194Sdelphij                state->mode = GZ_APPEND;
140205194Sdelphij                break;
141205194Sdelphij#endif
142205194Sdelphij            case '+':       /* can't read and write at the same time */
143205194Sdelphij                free(state);
144205194Sdelphij                return NULL;
145205194Sdelphij            case 'b':       /* ignore -- will request binary anyway */
146205194Sdelphij                break;
147237691Sdelphij#ifdef O_CLOEXEC
148237691Sdelphij            case 'e':
149237691Sdelphij                cloexec = 1;
150237691Sdelphij                break;
151237691Sdelphij#endif
152237691Sdelphij#ifdef O_EXCL
153237691Sdelphij            case 'x':
154237691Sdelphij                exclusive = 1;
155237691Sdelphij                break;
156237691Sdelphij#endif
157205194Sdelphij            case 'f':
158205194Sdelphij                state->strategy = Z_FILTERED;
159205194Sdelphij                break;
160205194Sdelphij            case 'h':
161205194Sdelphij                state->strategy = Z_HUFFMAN_ONLY;
162205194Sdelphij                break;
163205194Sdelphij            case 'R':
164205194Sdelphij                state->strategy = Z_RLE;
165205194Sdelphij                break;
166205194Sdelphij            case 'F':
167205194Sdelphij                state->strategy = Z_FIXED;
168254069Sdelphij                break;
169237691Sdelphij            case 'T':
170237691Sdelphij                state->direct = 1;
171254069Sdelphij                break;
172205194Sdelphij            default:        /* could consider as an error, but just ignore */
173205194Sdelphij                ;
174205194Sdelphij            }
175205194Sdelphij        mode++;
176205194Sdelphij    }
177205194Sdelphij
178205194Sdelphij    /* must provide an "r", "w", or "a" */
179205194Sdelphij    if (state->mode == GZ_NONE) {
180205194Sdelphij        free(state);
181205194Sdelphij        return NULL;
182205194Sdelphij    }
183205194Sdelphij
184237691Sdelphij    /* can't force transparent read */
185237691Sdelphij    if (state->mode == GZ_READ) {
186237691Sdelphij        if (state->direct) {
187237691Sdelphij            free(state);
188237691Sdelphij            return NULL;
189237691Sdelphij        }
190237691Sdelphij        state->direct = 1;      /* for empty file */
191237691Sdelphij    }
192237691Sdelphij
193205194Sdelphij    /* save the path name for error messages */
194237691Sdelphij#ifdef _WIN32
195237691Sdelphij    if (fd == -2) {
196237691Sdelphij        len = wcstombs(NULL, path, 0);
197237691Sdelphij        if (len == (size_t)-1)
198237691Sdelphij            len = 0;
199237691Sdelphij    }
200237691Sdelphij    else
201237691Sdelphij#endif
202254069Sdelphij        len = strlen((const char *)path);
203254069Sdelphij    state->path = (char *)malloc(len + 1);
204205194Sdelphij    if (state->path == NULL) {
205205194Sdelphij        free(state);
206205194Sdelphij        return NULL;
207205194Sdelphij    }
208237691Sdelphij#ifdef _WIN32
209237691Sdelphij    if (fd == -2)
210237691Sdelphij        if (len)
211237691Sdelphij            wcstombs(state->path, path, len + 1);
212237691Sdelphij        else
213237691Sdelphij            *(state->path) = 0;
214237691Sdelphij    else
215237691Sdelphij#endif
216254069Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
217254069Sdelphij        snprintf(state->path, len + 1, "%s", (const char *)path);
218254069Sdelphij#else
219237691Sdelphij        strcpy(state->path, path);
220254069Sdelphij#endif
221205194Sdelphij
222237691Sdelphij    /* compute the flags for open() */
223237691Sdelphij    oflag =
224205194Sdelphij#ifdef O_LARGEFILE
225237691Sdelphij        O_LARGEFILE |
226205194Sdelphij#endif
227205194Sdelphij#ifdef O_BINARY
228237691Sdelphij        O_BINARY |
229205194Sdelphij#endif
230237691Sdelphij#ifdef O_CLOEXEC
231237691Sdelphij        (cloexec ? O_CLOEXEC : 0) |
232237691Sdelphij#endif
233237691Sdelphij        (state->mode == GZ_READ ?
234237691Sdelphij         O_RDONLY :
235237691Sdelphij         (O_WRONLY | O_CREAT |
236237691Sdelphij#ifdef O_EXCL
237237691Sdelphij          (exclusive ? O_EXCL : 0) |
238237691Sdelphij#endif
239237691Sdelphij          (state->mode == GZ_WRITE ?
240237691Sdelphij           O_TRUNC :
241237691Sdelphij           O_APPEND)));
242237691Sdelphij
243237691Sdelphij    /* open the file with the appropriate flags (or just use fd) */
244237691Sdelphij    state->fd = fd > -1 ? fd : (
245237691Sdelphij#ifdef _WIN32
246237691Sdelphij        fd == -2 ? _wopen(path, oflag, 0666) :
247237691Sdelphij#endif
248254069Sdelphij        open((const char *)path, oflag, 0666));
249205194Sdelphij    if (state->fd == -1) {
250206708Sdelphij        free(state->path);
251205194Sdelphij        free(state);
252205194Sdelphij        return NULL;
253205194Sdelphij    }
254205194Sdelphij    if (state->mode == GZ_APPEND)
255205194Sdelphij        state->mode = GZ_WRITE;         /* simplify later checks */
256205194Sdelphij
257205194Sdelphij    /* save the current position for rewinding (only if reading) */
258205194Sdelphij    if (state->mode == GZ_READ) {
259205194Sdelphij        state->start = LSEEK(state->fd, 0, SEEK_CUR);
260205194Sdelphij        if (state->start == -1) state->start = 0;
261205194Sdelphij    }
262205194Sdelphij
263205194Sdelphij    /* initialize stream */
264205194Sdelphij    gz_reset(state);
265205194Sdelphij
266205194Sdelphij    /* return stream */
267205194Sdelphij    return (gzFile)state;
268205194Sdelphij}
269205194Sdelphij
270205194Sdelphij/* -- see zlib.h -- */
271205194SdelphijgzFile ZEXPORT gzopen(path, mode)
272205194Sdelphij    const char *path;
273205194Sdelphij    const char *mode;
274205194Sdelphij{
275205194Sdelphij    return gz_open(path, -1, mode);
276205194Sdelphij}
277205194Sdelphij
278205194Sdelphij/* -- see zlib.h -- */
279205194SdelphijgzFile ZEXPORT gzopen64(path, mode)
280205194Sdelphij    const char *path;
281205194Sdelphij    const char *mode;
282205194Sdelphij{
283205194Sdelphij    return gz_open(path, -1, mode);
284205194Sdelphij}
285205194Sdelphij
286205194Sdelphij/* -- see zlib.h -- */
287205194SdelphijgzFile ZEXPORT gzdopen(fd, mode)
288205194Sdelphij    int fd;
289205194Sdelphij    const char *mode;
290205194Sdelphij{
291205194Sdelphij    char *path;         /* identifier for error messages */
292205194Sdelphij    gzFile gz;
293205194Sdelphij
294254069Sdelphij    if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
295205194Sdelphij        return NULL;
296254069Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
297254069Sdelphij    snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */
298254069Sdelphij#else
299206002Sdelphij    sprintf(path, "<fd:%d>", fd);   /* for debugging */
300254069Sdelphij#endif
301205194Sdelphij    gz = gz_open(path, fd, mode);
302205194Sdelphij    free(path);
303205194Sdelphij    return gz;
304205194Sdelphij}
305205194Sdelphij
306205194Sdelphij/* -- see zlib.h -- */
307237691Sdelphij#ifdef _WIN32
308237691SdelphijgzFile ZEXPORT gzopen_w(path, mode)
309237691Sdelphij    const wchar_t *path;
310237691Sdelphij    const char *mode;
311237691Sdelphij{
312237691Sdelphij    return gz_open(path, -2, mode);
313237691Sdelphij}
314237691Sdelphij#endif
315237691Sdelphij
316237691Sdelphij/* -- see zlib.h -- */
317205194Sdelphijint ZEXPORT gzbuffer(file, size)
318205194Sdelphij    gzFile file;
319205194Sdelphij    unsigned size;
320205194Sdelphij{
321205194Sdelphij    gz_statep state;
322205194Sdelphij
323205194Sdelphij    /* get internal structure and check integrity */
324205194Sdelphij    if (file == NULL)
325205194Sdelphij        return -1;
326205194Sdelphij    state = (gz_statep)file;
327205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
328205194Sdelphij        return -1;
329205194Sdelphij
330205194Sdelphij    /* make sure we haven't already allocated memory */
331205194Sdelphij    if (state->size != 0)
332205194Sdelphij        return -1;
333205194Sdelphij
334205194Sdelphij    /* check and set requested size */
335237691Sdelphij    if (size < 2)
336237691Sdelphij        size = 2;               /* need two bytes to check magic header */
337205194Sdelphij    state->want = size;
338205194Sdelphij    return 0;
339205194Sdelphij}
340205194Sdelphij
341205194Sdelphij/* -- see zlib.h -- */
342205194Sdelphijint ZEXPORT gzrewind(file)
343205194Sdelphij    gzFile file;
344205194Sdelphij{
345205194Sdelphij    gz_statep state;
346205194Sdelphij
347205194Sdelphij    /* get internal structure */
348205194Sdelphij    if (file == NULL)
349205194Sdelphij        return -1;
350205194Sdelphij    state = (gz_statep)file;
351205194Sdelphij
352205194Sdelphij    /* check that we're reading and that there's no error */
353237691Sdelphij    if (state->mode != GZ_READ ||
354237691Sdelphij            (state->err != Z_OK && state->err != Z_BUF_ERROR))
355205194Sdelphij        return -1;
356205194Sdelphij
357205194Sdelphij    /* back up and start over */
358205194Sdelphij    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
359205194Sdelphij        return -1;
360205194Sdelphij    gz_reset(state);
361205194Sdelphij    return 0;
362205194Sdelphij}
363205194Sdelphij
364205194Sdelphij/* -- see zlib.h -- */
365205194Sdelphijz_off64_t ZEXPORT gzseek64(file, offset, whence)
366205194Sdelphij    gzFile file;
367205194Sdelphij    z_off64_t offset;
368205194Sdelphij    int whence;
369205194Sdelphij{
370205194Sdelphij    unsigned n;
371205194Sdelphij    z_off64_t ret;
372205194Sdelphij    gz_statep state;
373205194Sdelphij
374205194Sdelphij    /* get internal structure and check integrity */
375205194Sdelphij    if (file == NULL)
376205194Sdelphij        return -1;
377205194Sdelphij    state = (gz_statep)file;
378205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
379205194Sdelphij        return -1;
380205194Sdelphij
381205194Sdelphij    /* check that there's no error */
382237691Sdelphij    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
383205194Sdelphij        return -1;
384205194Sdelphij
385205194Sdelphij    /* can only seek from start or relative to current position */
386205194Sdelphij    if (whence != SEEK_SET && whence != SEEK_CUR)
387205194Sdelphij        return -1;
388205194Sdelphij
389205194Sdelphij    /* normalize offset to a SEEK_CUR specification */
390205194Sdelphij    if (whence == SEEK_SET)
391237691Sdelphij        offset -= state->x.pos;
392205194Sdelphij    else if (state->seek)
393205194Sdelphij        offset += state->skip;
394205194Sdelphij    state->seek = 0;
395205194Sdelphij
396205194Sdelphij    /* if within raw area while reading, just go there */
397205194Sdelphij    if (state->mode == GZ_READ && state->how == COPY &&
398237691Sdelphij            state->x.pos + offset >= 0) {
399237691Sdelphij        ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
400205194Sdelphij        if (ret == -1)
401205194Sdelphij            return -1;
402237691Sdelphij        state->x.have = 0;
403205194Sdelphij        state->eof = 0;
404237691Sdelphij        state->past = 0;
405205194Sdelphij        state->seek = 0;
406205194Sdelphij        gz_error(state, Z_OK, NULL);
407205194Sdelphij        state->strm.avail_in = 0;
408237691Sdelphij        state->x.pos += offset;
409237691Sdelphij        return state->x.pos;
410205194Sdelphij    }
411205194Sdelphij
412205194Sdelphij    /* calculate skip amount, rewinding if needed for back seek when reading */
413205194Sdelphij    if (offset < 0) {
414205194Sdelphij        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
415205194Sdelphij            return -1;
416237691Sdelphij        offset += state->x.pos;
417205194Sdelphij        if (offset < 0)                     /* before start of file! */
418205194Sdelphij            return -1;
419205194Sdelphij        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
420205194Sdelphij            return -1;
421205194Sdelphij    }
422205194Sdelphij
423205194Sdelphij    /* if reading, skip what's in output buffer (one less gzgetc() check) */
424205194Sdelphij    if (state->mode == GZ_READ) {
425237691Sdelphij        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
426237691Sdelphij            (unsigned)offset : state->x.have;
427237691Sdelphij        state->x.have -= n;
428237691Sdelphij        state->x.next += n;
429237691Sdelphij        state->x.pos += n;
430205194Sdelphij        offset -= n;
431205194Sdelphij    }
432205194Sdelphij
433205194Sdelphij    /* request skip (if not zero) */
434205194Sdelphij    if (offset) {
435205194Sdelphij        state->seek = 1;
436205194Sdelphij        state->skip = offset;
437205194Sdelphij    }
438237691Sdelphij    return state->x.pos + offset;
439205194Sdelphij}
440205194Sdelphij
441205194Sdelphij/* -- see zlib.h -- */
442205194Sdelphijz_off_t ZEXPORT gzseek(file, offset, whence)
443205194Sdelphij    gzFile file;
444205194Sdelphij    z_off_t offset;
445205194Sdelphij    int whence;
446205194Sdelphij{
447205194Sdelphij    z_off64_t ret;
448205194Sdelphij
449205194Sdelphij    ret = gzseek64(file, (z_off64_t)offset, whence);
450205194Sdelphij    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
451205194Sdelphij}
452205194Sdelphij
453205194Sdelphij/* -- see zlib.h -- */
454205194Sdelphijz_off64_t ZEXPORT gztell64(file)
455205194Sdelphij    gzFile file;
456205194Sdelphij{
457205194Sdelphij    gz_statep state;
458205194Sdelphij
459205194Sdelphij    /* get internal structure and check integrity */
460205194Sdelphij    if (file == NULL)
461205194Sdelphij        return -1;
462205194Sdelphij    state = (gz_statep)file;
463205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
464205194Sdelphij        return -1;
465205194Sdelphij
466205194Sdelphij    /* return position */
467237691Sdelphij    return state->x.pos + (state->seek ? state->skip : 0);
468205194Sdelphij}
469205194Sdelphij
470205194Sdelphij/* -- see zlib.h -- */
471205194Sdelphijz_off_t ZEXPORT gztell(file)
472205194Sdelphij    gzFile file;
473205194Sdelphij{
474205194Sdelphij    z_off64_t ret;
475205194Sdelphij
476205194Sdelphij    ret = gztell64(file);
477205194Sdelphij    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
478205194Sdelphij}
479205194Sdelphij
480205194Sdelphij/* -- see zlib.h -- */
481205194Sdelphijz_off64_t ZEXPORT gzoffset64(file)
482205194Sdelphij    gzFile file;
483205194Sdelphij{
484205194Sdelphij    z_off64_t offset;
485205194Sdelphij    gz_statep state;
486205194Sdelphij
487205194Sdelphij    /* get internal structure and check integrity */
488205194Sdelphij    if (file == NULL)
489205194Sdelphij        return -1;
490205194Sdelphij    state = (gz_statep)file;
491205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
492205194Sdelphij        return -1;
493205194Sdelphij
494205194Sdelphij    /* compute and return effective offset in file */
495205194Sdelphij    offset = LSEEK(state->fd, 0, SEEK_CUR);
496205194Sdelphij    if (offset == -1)
497205194Sdelphij        return -1;
498205194Sdelphij    if (state->mode == GZ_READ)             /* reading */
499205194Sdelphij        offset -= state->strm.avail_in;     /* don't count buffered input */
500205194Sdelphij    return offset;
501205194Sdelphij}
502205194Sdelphij
503205194Sdelphij/* -- see zlib.h -- */
504205194Sdelphijz_off_t ZEXPORT gzoffset(file)
505205194Sdelphij    gzFile file;
506205194Sdelphij{
507205194Sdelphij    z_off64_t ret;
508205194Sdelphij
509205194Sdelphij    ret = gzoffset64(file);
510205194Sdelphij    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
511205194Sdelphij}
512205194Sdelphij
513205194Sdelphij/* -- see zlib.h -- */
514205194Sdelphijint ZEXPORT gzeof(file)
515205194Sdelphij    gzFile file;
516205194Sdelphij{
517205194Sdelphij    gz_statep state;
518205194Sdelphij
519205194Sdelphij    /* get internal structure and check integrity */
520205194Sdelphij    if (file == NULL)
521205194Sdelphij        return 0;
522205194Sdelphij    state = (gz_statep)file;
523205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
524205194Sdelphij        return 0;
525205194Sdelphij
526205194Sdelphij    /* return end-of-file state */
527237691Sdelphij    return state->mode == GZ_READ ? state->past : 0;
528205194Sdelphij}
529205194Sdelphij
530205194Sdelphij/* -- see zlib.h -- */
531205194Sdelphijconst char * ZEXPORT gzerror(file, errnum)
532205194Sdelphij    gzFile file;
533205194Sdelphij    int *errnum;
534205194Sdelphij{
535205194Sdelphij    gz_statep state;
536205194Sdelphij
537205194Sdelphij    /* get internal structure and check integrity */
538205194Sdelphij    if (file == NULL)
539205194Sdelphij        return NULL;
540205194Sdelphij    state = (gz_statep)file;
541205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
542205194Sdelphij        return NULL;
543205194Sdelphij
544205194Sdelphij    /* return error information */
545205194Sdelphij    if (errnum != NULL)
546205194Sdelphij        *errnum = state->err;
547254069Sdelphij    return state->err == Z_MEM_ERROR ? "out of memory" :
548254069Sdelphij                                       (state->msg == NULL ? "" : state->msg);
549205194Sdelphij}
550205194Sdelphij
551205194Sdelphij/* -- see zlib.h -- */
552205194Sdelphijvoid ZEXPORT gzclearerr(file)
553205194Sdelphij    gzFile file;
554205194Sdelphij{
555205194Sdelphij    gz_statep state;
556205194Sdelphij
557205194Sdelphij    /* get internal structure and check integrity */
558205194Sdelphij    if (file == NULL)
559205194Sdelphij        return;
560205194Sdelphij    state = (gz_statep)file;
561205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
562205194Sdelphij        return;
563205194Sdelphij
564205194Sdelphij    /* clear error and end-of-file */
565237691Sdelphij    if (state->mode == GZ_READ) {
566205194Sdelphij        state->eof = 0;
567237691Sdelphij        state->past = 0;
568237691Sdelphij    }
569205194Sdelphij    gz_error(state, Z_OK, NULL);
570205194Sdelphij}
571205194Sdelphij
572205194Sdelphij/* Create an error message in allocated memory and set state->err and
573205194Sdelphij   state->msg accordingly.  Free any previous error message already there.  Do
574205194Sdelphij   not try to free or allocate space if the error is Z_MEM_ERROR (out of
575205194Sdelphij   memory).  Simply save the error message as a static string.  If there is an
576205194Sdelphij   allocation failure constructing the error message, then convert the error to
577205194Sdelphij   out of memory. */
578206924Sdelphijvoid ZLIB_INTERNAL gz_error(state, err, msg)
579205194Sdelphij    gz_statep state;
580205194Sdelphij    int err;
581205194Sdelphij    const char *msg;
582205194Sdelphij{
583205194Sdelphij    /* free previously allocated message and clear */
584205194Sdelphij    if (state->msg != NULL) {
585205194Sdelphij        if (state->err != Z_MEM_ERROR)
586205194Sdelphij            free(state->msg);
587205194Sdelphij        state->msg = NULL;
588205194Sdelphij    }
589205194Sdelphij
590237691Sdelphij    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
591237691Sdelphij    if (err != Z_OK && err != Z_BUF_ERROR)
592237691Sdelphij        state->x.have = 0;
593237691Sdelphij
594205194Sdelphij    /* set error code, and if no message, then done */
595205194Sdelphij    state->err = err;
596205194Sdelphij    if (msg == NULL)
597205194Sdelphij        return;
598205194Sdelphij
599254069Sdelphij    /* for an out of memory error, return literal string when requested */
600254069Sdelphij    if (err == Z_MEM_ERROR)
601205194Sdelphij        return;
602205194Sdelphij
603205194Sdelphij    /* construct error message with path */
604254069Sdelphij    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
605254069Sdelphij            NULL) {
606205194Sdelphij        state->err = Z_MEM_ERROR;
607205194Sdelphij        return;
608205194Sdelphij    }
609254069Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
610254069Sdelphij    snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
611254069Sdelphij             "%s%s%s", state->path, ": ", msg);
612254069Sdelphij#else
613205194Sdelphij    strcpy(state->msg, state->path);
614205194Sdelphij    strcat(state->msg, ": ");
615205194Sdelphij    strcat(state->msg, msg);
616254069Sdelphij#endif
617205194Sdelphij    return;
618205194Sdelphij}
619205194Sdelphij
620205194Sdelphij#ifndef INT_MAX
621205194Sdelphij/* portably return maximum value for an int (when limits.h presumed not
622205194Sdelphij   available) -- we need to do this to cover cases where 2's complement not
623205194Sdelphij   used, since C standard permits 1's complement and sign-bit representations,
624205194Sdelphij   otherwise we could just use ((unsigned)-1) >> 1 */
625206924Sdelphijunsigned ZLIB_INTERNAL gz_intmax()
626205194Sdelphij{
627205194Sdelphij    unsigned p, q;
628205194Sdelphij
629205194Sdelphij    p = 1;
630205194Sdelphij    do {
631205194Sdelphij        q = p;
632205194Sdelphij        p <<= 1;
633205194Sdelphij        p++;
634205194Sdelphij    } while (p > q);
635205194Sdelphij    return q >> 1;
636205194Sdelphij}
637205194Sdelphij#endif
638