1205194Sdelphij/* gzlib.c -- zlib functions common to reading and writing gzip files
2250261Sdelphij * 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
11237410Sdelphij#if defined(_WIN32) && !defined(__BORLANDC__)
12237410Sdelphij#  define LSEEK _lseeki64
13237410Sdelphij#else
14206708Sdelphij#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
15205194Sdelphij#  define LSEEK lseek64
16205194Sdelphij#else
17205194Sdelphij#  define LSEEK lseek
18205194Sdelphij#endif
19237410Sdelphij#endif
20205194Sdelphij
21205194Sdelphij/* Local functions */
22205194Sdelphijlocal void gz_reset OF((gz_statep));
23237410Sdelphijlocal 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{
81237410Sdelphij    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 */
84237410Sdelphij        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 */
89237410Sdelphij    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)
95237410Sdelphij    const void *path;
96205194Sdelphij    int fd;
97205194Sdelphij    const char *mode;
98205194Sdelphij{
99205194Sdelphij    gz_statep state;
100237410Sdelphij    size_t len;
101237410Sdelphij    int oflag;
102237410Sdelphij#ifdef O_CLOEXEC
103237410Sdelphij    int cloexec = 0;
104237410Sdelphij#endif
105237410Sdelphij#ifdef O_EXCL
106237410Sdelphij    int exclusive = 0;
107237410Sdelphij#endif
108205194Sdelphij
109237410Sdelphij    /* check input */
110237410Sdelphij    if (path == NULL)
111237410Sdelphij        return NULL;
112237410Sdelphij
113205194Sdelphij    /* allocate gzFile structure to return */
114250261Sdelphij    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;
125237410Sdelphij    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;
147237410Sdelphij#ifdef O_CLOEXEC
148237410Sdelphij            case 'e':
149237410Sdelphij                cloexec = 1;
150237410Sdelphij                break;
151237410Sdelphij#endif
152237410Sdelphij#ifdef O_EXCL
153237410Sdelphij            case 'x':
154237410Sdelphij                exclusive = 1;
155237410Sdelphij                break;
156237410Sdelphij#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;
168250261Sdelphij                break;
169237410Sdelphij            case 'T':
170237410Sdelphij                state->direct = 1;
171250261Sdelphij                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
184237410Sdelphij    /* can't force transparent read */
185237410Sdelphij    if (state->mode == GZ_READ) {
186237410Sdelphij        if (state->direct) {
187237410Sdelphij            free(state);
188237410Sdelphij            return NULL;
189237410Sdelphij        }
190237410Sdelphij        state->direct = 1;      /* for empty file */
191237410Sdelphij    }
192237410Sdelphij
193205194Sdelphij    /* save the path name for error messages */
194237410Sdelphij#ifdef _WIN32
195237410Sdelphij    if (fd == -2) {
196237410Sdelphij        len = wcstombs(NULL, path, 0);
197237410Sdelphij        if (len == (size_t)-1)
198237410Sdelphij            len = 0;
199237410Sdelphij    }
200237410Sdelphij    else
201237410Sdelphij#endif
202250261Sdelphij        len = strlen((const char *)path);
203250261Sdelphij    state->path = (char *)malloc(len + 1);
204205194Sdelphij    if (state->path == NULL) {
205205194Sdelphij        free(state);
206205194Sdelphij        return NULL;
207205194Sdelphij    }
208237410Sdelphij#ifdef _WIN32
209237410Sdelphij    if (fd == -2)
210237410Sdelphij        if (len)
211237410Sdelphij            wcstombs(state->path, path, len + 1);
212237410Sdelphij        else
213237410Sdelphij            *(state->path) = 0;
214237410Sdelphij    else
215237410Sdelphij#endif
216250261Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
217250261Sdelphij        snprintf(state->path, len + 1, "%s", (const char *)path);
218250261Sdelphij#else
219237410Sdelphij        strcpy(state->path, path);
220250261Sdelphij#endif
221205194Sdelphij
222237410Sdelphij    /* compute the flags for open() */
223237410Sdelphij    oflag =
224205194Sdelphij#ifdef O_LARGEFILE
225237410Sdelphij        O_LARGEFILE |
226205194Sdelphij#endif
227205194Sdelphij#ifdef O_BINARY
228237410Sdelphij        O_BINARY |
229205194Sdelphij#endif
230237410Sdelphij#ifdef O_CLOEXEC
231237410Sdelphij        (cloexec ? O_CLOEXEC : 0) |
232237410Sdelphij#endif
233237410Sdelphij        (state->mode == GZ_READ ?
234237410Sdelphij         O_RDONLY :
235237410Sdelphij         (O_WRONLY | O_CREAT |
236237410Sdelphij#ifdef O_EXCL
237237410Sdelphij          (exclusive ? O_EXCL : 0) |
238237410Sdelphij#endif
239237410Sdelphij          (state->mode == GZ_WRITE ?
240237410Sdelphij           O_TRUNC :
241237410Sdelphij           O_APPEND)));
242237410Sdelphij
243237410Sdelphij    /* open the file with the appropriate flags (or just use fd) */
244237410Sdelphij    state->fd = fd > -1 ? fd : (
245237410Sdelphij#ifdef _WIN32
246237410Sdelphij        fd == -2 ? _wopen(path, oflag, 0666) :
247237410Sdelphij#endif
248250261Sdelphij        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
294250261Sdelphij    if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
295205194Sdelphij        return NULL;
296250261Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
297250261Sdelphij    snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd); /* for debugging */
298250261Sdelphij#else
299206002Sdelphij    sprintf(path, "<fd:%d>", fd);   /* for debugging */
300250261Sdelphij#endif
301205194Sdelphij    gz = gz_open(path, fd, mode);
302205194Sdelphij    free(path);
303205194Sdelphij    return gz;
304205194Sdelphij}
305205194Sdelphij
306205194Sdelphij/* -- see zlib.h -- */
307237410Sdelphij#ifdef _WIN32
308237410SdelphijgzFile ZEXPORT gzopen_w(path, mode)
309237410Sdelphij    const wchar_t *path;
310237410Sdelphij    const char *mode;
311237410Sdelphij{
312237410Sdelphij    return gz_open(path, -2, mode);
313237410Sdelphij}
314237410Sdelphij#endif
315237410Sdelphij
316237410Sdelphij/* -- 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 */
335237410Sdelphij    if (size < 2)
336237410Sdelphij        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 */
353237410Sdelphij    if (state->mode != GZ_READ ||
354237410Sdelphij            (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 */
382237410Sdelphij    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)
391237410Sdelphij        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 &&
398237410Sdelphij            state->x.pos + offset >= 0) {
399237410Sdelphij        ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
400205194Sdelphij        if (ret == -1)
401205194Sdelphij            return -1;
402237410Sdelphij        state->x.have = 0;
403205194Sdelphij        state->eof = 0;
404237410Sdelphij        state->past = 0;
405205194Sdelphij        state->seek = 0;
406205194Sdelphij        gz_error(state, Z_OK, NULL);
407205194Sdelphij        state->strm.avail_in = 0;
408237410Sdelphij        state->x.pos += offset;
409237410Sdelphij        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;
416237410Sdelphij        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) {
425237410Sdelphij        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
426237410Sdelphij            (unsigned)offset : state->x.have;
427237410Sdelphij        state->x.have -= n;
428237410Sdelphij        state->x.next += n;
429237410Sdelphij        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    }
438237410Sdelphij    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 */
467237410Sdelphij    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 */
527237410Sdelphij    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;
547250261Sdelphij    return state->err == Z_MEM_ERROR ? "out of memory" :
548250261Sdelphij                                       (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 */
565237410Sdelphij    if (state->mode == GZ_READ) {
566205194Sdelphij        state->eof = 0;
567237410Sdelphij        state->past = 0;
568237410Sdelphij    }
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
590237410Sdelphij    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
591237410Sdelphij    if (err != Z_OK && err != Z_BUF_ERROR)
592237410Sdelphij        state->x.have = 0;
593237410Sdelphij
594205194Sdelphij    /* set error code, and if no message, then done */
595205194Sdelphij    state->err = err;
596205194Sdelphij    if (msg == NULL)
597205194Sdelphij        return;
598205194Sdelphij
599250261Sdelphij    /* for an out of memory error, return literal string when requested */
600250261Sdelphij    if (err == Z_MEM_ERROR)
601205194Sdelphij        return;
602205194Sdelphij
603205194Sdelphij    /* construct error message with path */
604250261Sdelphij    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
605250261Sdelphij            NULL) {
606205194Sdelphij        state->err = Z_MEM_ERROR;
607205194Sdelphij        return;
608205194Sdelphij    }
609250261Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
610250261Sdelphij    snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
611250261Sdelphij             "%s%s%s", state->path, ": ", msg);
612250261Sdelphij#else
613205194Sdelphij    strcpy(state->msg, state->path);
614205194Sdelphij    strcat(state->msg, ": ");
615205194Sdelphij    strcat(state->msg, msg);
616250261Sdelphij#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