1205194Sdelphij/* gzlib.c -- zlib functions common to reading and writing gzip files
2312335Sdelphij * Copyright (C) 2004-2017 Mark Adler
3205194Sdelphij * For conditions of distribution and use, see copyright notice in zlib.h
4205194Sdelphij */
5205194Sdelphij
6311275Sdelphij/* $FreeBSD: stable/11/sys/contrib/zlib/gzlib.c 312335 2017-01-17 05:55:47Z delphij $ */
7311275Sdelphij
8205194Sdelphij#include "gzguts.h"
9311275Sdelphij#include "zutil.h"
10205194Sdelphij
11311285Sdelphij#if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__)
12230837Sdelphij#  define LSEEK _lseeki64
13230837Sdelphij#else
14206499Sdelphij#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
15205194Sdelphij#  define LSEEK lseek64
16205194Sdelphij#else
17205194Sdelphij#  define LSEEK lseek
18205194Sdelphij#endif
19230837Sdelphij#endif
20205194Sdelphij
21205194Sdelphij/* Local functions */
22205194Sdelphijlocal void gz_reset OF((gz_statep));
23237248Sdelphijlocal gzFile gz_open OF((const void *, int, const char *));
24205194Sdelphij
25205990Sdelphij#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. */
36206905Sdelphijchar 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
75205990Sdelphij#endif /* UNDER_CE */
76205194Sdelphij
77205194Sdelphij/* Reset gzip file state */
78205194Sdelphijlocal void gz_reset(state)
79205194Sdelphij    gz_statep state;
80205194Sdelphij{
81230837Sdelphij    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 */
84230837Sdelphij        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 */
89230837Sdelphij    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)
95237248Sdelphij    const void *path;
96205194Sdelphij    int fd;
97205194Sdelphij    const char *mode;
98205194Sdelphij{
99205194Sdelphij    gz_statep state;
100311285Sdelphij    z_size_t len;
101237248Sdelphij    int oflag;
102237248Sdelphij#ifdef O_CLOEXEC
103237248Sdelphij    int cloexec = 0;
104237248Sdelphij#endif
105237248Sdelphij#ifdef O_EXCL
106237248Sdelphij    int exclusive = 0;
107237248Sdelphij#endif
108205194Sdelphij
109230837Sdelphij    /* check input */
110230837Sdelphij    if (path == NULL)
111230837Sdelphij        return NULL;
112230837Sdelphij
113205194Sdelphij    /* allocate gzFile structure to return */
114250224Sdelphij    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;
125230837Sdelphij    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;
147237248Sdelphij#ifdef O_CLOEXEC
148237248Sdelphij            case 'e':
149237248Sdelphij                cloexec = 1;
150237248Sdelphij                break;
151237248Sdelphij#endif
152237248Sdelphij#ifdef O_EXCL
153237248Sdelphij            case 'x':
154237248Sdelphij                exclusive = 1;
155237248Sdelphij                break;
156237248Sdelphij#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;
168250224Sdelphij                break;
169230837Sdelphij            case 'T':
170230837Sdelphij                state->direct = 1;
171250224Sdelphij                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
184230837Sdelphij    /* can't force transparent read */
185230837Sdelphij    if (state->mode == GZ_READ) {
186230837Sdelphij        if (state->direct) {
187230837Sdelphij            free(state);
188230837Sdelphij            return NULL;
189230837Sdelphij        }
190230837Sdelphij        state->direct = 1;      /* for empty file */
191230837Sdelphij    }
192230837Sdelphij
193205194Sdelphij    /* save the path name for error messages */
194311285Sdelphij#ifdef WIDECHAR
195237248Sdelphij    if (fd == -2) {
196237248Sdelphij        len = wcstombs(NULL, path, 0);
197311285Sdelphij        if (len == (z_size_t)-1)
198237248Sdelphij            len = 0;
199237248Sdelphij    }
200237248Sdelphij    else
201237248Sdelphij#endif
202250224Sdelphij        len = strlen((const char *)path);
203250224Sdelphij    state->path = (char *)malloc(len + 1);
204205194Sdelphij    if (state->path == NULL) {
205205194Sdelphij        free(state);
206205194Sdelphij        return NULL;
207205194Sdelphij    }
208311285Sdelphij#ifdef WIDECHAR
209237248Sdelphij    if (fd == -2)
210237248Sdelphij        if (len)
211237248Sdelphij            wcstombs(state->path, path, len + 1);
212237248Sdelphij        else
213237248Sdelphij            *(state->path) = 0;
214237248Sdelphij    else
215237248Sdelphij#endif
216250224Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
217311285Sdelphij        (void)snprintf(state->path, len + 1, "%s", (const char *)path);
218250224Sdelphij#else
219237248Sdelphij        strcpy(state->path, path);
220250224Sdelphij#endif
221205194Sdelphij
222237248Sdelphij    /* compute the flags for open() */
223237248Sdelphij    oflag =
224205194Sdelphij#ifdef O_LARGEFILE
225237248Sdelphij        O_LARGEFILE |
226205194Sdelphij#endif
227205194Sdelphij#ifdef O_BINARY
228237248Sdelphij        O_BINARY |
229205194Sdelphij#endif
230237248Sdelphij#ifdef O_CLOEXEC
231237248Sdelphij        (cloexec ? O_CLOEXEC : 0) |
232237248Sdelphij#endif
233237248Sdelphij        (state->mode == GZ_READ ?
234237248Sdelphij         O_RDONLY :
235237248Sdelphij         (O_WRONLY | O_CREAT |
236237248Sdelphij#ifdef O_EXCL
237237248Sdelphij          (exclusive ? O_EXCL : 0) |
238237248Sdelphij#endif
239237248Sdelphij          (state->mode == GZ_WRITE ?
240237248Sdelphij           O_TRUNC :
241237248Sdelphij           O_APPEND)));
242237248Sdelphij
243237248Sdelphij    /* open the file with the appropriate flags (or just use fd) */
244237248Sdelphij    state->fd = fd > -1 ? fd : (
245311285Sdelphij#ifdef WIDECHAR
246237248Sdelphij        fd == -2 ? _wopen(path, oflag, 0666) :
247237248Sdelphij#endif
248250224Sdelphij        open((const char *)path, oflag, 0666));
249205194Sdelphij    if (state->fd == -1) {
250206499Sdelphij        free(state->path);
251205194Sdelphij        free(state);
252205194Sdelphij        return NULL;
253205194Sdelphij    }
254311285Sdelphij    if (state->mode == GZ_APPEND) {
255311285Sdelphij        LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
256205194Sdelphij        state->mode = GZ_WRITE;         /* simplify later checks */
257311285Sdelphij    }
258205194Sdelphij
259205194Sdelphij    /* save the current position for rewinding (only if reading) */
260205194Sdelphij    if (state->mode == GZ_READ) {
261205194Sdelphij        state->start = LSEEK(state->fd, 0, SEEK_CUR);
262205194Sdelphij        if (state->start == -1) state->start = 0;
263205194Sdelphij    }
264205194Sdelphij
265205194Sdelphij    /* initialize stream */
266205194Sdelphij    gz_reset(state);
267205194Sdelphij
268205194Sdelphij    /* return stream */
269205194Sdelphij    return (gzFile)state;
270205194Sdelphij}
271205194Sdelphij
272205194Sdelphij/* -- see zlib.h -- */
273205194SdelphijgzFile ZEXPORT gzopen(path, mode)
274205194Sdelphij    const char *path;
275205194Sdelphij    const char *mode;
276205194Sdelphij{
277205194Sdelphij    return gz_open(path, -1, mode);
278205194Sdelphij}
279205194Sdelphij
280205194Sdelphij/* -- see zlib.h -- */
281205194SdelphijgzFile ZEXPORT gzopen64(path, mode)
282205194Sdelphij    const char *path;
283205194Sdelphij    const char *mode;
284205194Sdelphij{
285205194Sdelphij    return gz_open(path, -1, mode);
286205194Sdelphij}
287205194Sdelphij
288205194Sdelphij/* -- see zlib.h -- */
289205194SdelphijgzFile ZEXPORT gzdopen(fd, mode)
290205194Sdelphij    int fd;
291205194Sdelphij    const char *mode;
292205194Sdelphij{
293205194Sdelphij    char *path;         /* identifier for error messages */
294205194Sdelphij    gzFile gz;
295205194Sdelphij
296250224Sdelphij    if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
297205194Sdelphij        return NULL;
298250224Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
299311285Sdelphij    (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
300250224Sdelphij#else
301205990Sdelphij    sprintf(path, "<fd:%d>", fd);   /* for debugging */
302250224Sdelphij#endif
303205194Sdelphij    gz = gz_open(path, fd, mode);
304205194Sdelphij    free(path);
305205194Sdelphij    return gz;
306205194Sdelphij}
307205194Sdelphij
308205194Sdelphij/* -- see zlib.h -- */
309311285Sdelphij#ifdef WIDECHAR
310237248SdelphijgzFile ZEXPORT gzopen_w(path, mode)
311237248Sdelphij    const wchar_t *path;
312237248Sdelphij    const char *mode;
313237248Sdelphij{
314237248Sdelphij    return gz_open(path, -2, mode);
315237248Sdelphij}
316237248Sdelphij#endif
317237248Sdelphij
318237248Sdelphij/* -- see zlib.h -- */
319205194Sdelphijint ZEXPORT gzbuffer(file, size)
320205194Sdelphij    gzFile file;
321205194Sdelphij    unsigned size;
322205194Sdelphij{
323205194Sdelphij    gz_statep state;
324205194Sdelphij
325205194Sdelphij    /* get internal structure and check integrity */
326205194Sdelphij    if (file == NULL)
327205194Sdelphij        return -1;
328205194Sdelphij    state = (gz_statep)file;
329205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
330205194Sdelphij        return -1;
331205194Sdelphij
332205194Sdelphij    /* make sure we haven't already allocated memory */
333205194Sdelphij    if (state->size != 0)
334205194Sdelphij        return -1;
335205194Sdelphij
336205194Sdelphij    /* check and set requested size */
337311285Sdelphij    if ((size << 1) < size)
338311285Sdelphij        return -1;              /* need to be able to double it */
339230837Sdelphij    if (size < 2)
340230837Sdelphij        size = 2;               /* need two bytes to check magic header */
341205194Sdelphij    state->want = size;
342205194Sdelphij    return 0;
343205194Sdelphij}
344205194Sdelphij
345205194Sdelphij/* -- see zlib.h -- */
346205194Sdelphijint ZEXPORT gzrewind(file)
347205194Sdelphij    gzFile file;
348205194Sdelphij{
349205194Sdelphij    gz_statep state;
350205194Sdelphij
351205194Sdelphij    /* get internal structure */
352205194Sdelphij    if (file == NULL)
353205194Sdelphij        return -1;
354205194Sdelphij    state = (gz_statep)file;
355205194Sdelphij
356205194Sdelphij    /* check that we're reading and that there's no error */
357230837Sdelphij    if (state->mode != GZ_READ ||
358230837Sdelphij            (state->err != Z_OK && state->err != Z_BUF_ERROR))
359205194Sdelphij        return -1;
360205194Sdelphij
361205194Sdelphij    /* back up and start over */
362205194Sdelphij    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
363205194Sdelphij        return -1;
364205194Sdelphij    gz_reset(state);
365205194Sdelphij    return 0;
366205194Sdelphij}
367205194Sdelphij
368205194Sdelphij/* -- see zlib.h -- */
369205194Sdelphijz_off64_t ZEXPORT gzseek64(file, offset, whence)
370205194Sdelphij    gzFile file;
371205194Sdelphij    z_off64_t offset;
372205194Sdelphij    int whence;
373205194Sdelphij{
374205194Sdelphij    unsigned n;
375205194Sdelphij    z_off64_t ret;
376205194Sdelphij    gz_statep state;
377205194Sdelphij
378205194Sdelphij    /* get internal structure and check integrity */
379205194Sdelphij    if (file == NULL)
380205194Sdelphij        return -1;
381205194Sdelphij    state = (gz_statep)file;
382205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
383205194Sdelphij        return -1;
384205194Sdelphij
385205194Sdelphij    /* check that there's no error */
386230837Sdelphij    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
387205194Sdelphij        return -1;
388205194Sdelphij
389205194Sdelphij    /* can only seek from start or relative to current position */
390205194Sdelphij    if (whence != SEEK_SET && whence != SEEK_CUR)
391205194Sdelphij        return -1;
392205194Sdelphij
393205194Sdelphij    /* normalize offset to a SEEK_CUR specification */
394205194Sdelphij    if (whence == SEEK_SET)
395230837Sdelphij        offset -= state->x.pos;
396205194Sdelphij    else if (state->seek)
397205194Sdelphij        offset += state->skip;
398205194Sdelphij    state->seek = 0;
399205194Sdelphij
400205194Sdelphij    /* if within raw area while reading, just go there */
401205194Sdelphij    if (state->mode == GZ_READ && state->how == COPY &&
402230837Sdelphij            state->x.pos + offset >= 0) {
403230837Sdelphij        ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
404205194Sdelphij        if (ret == -1)
405205194Sdelphij            return -1;
406230837Sdelphij        state->x.have = 0;
407205194Sdelphij        state->eof = 0;
408230837Sdelphij        state->past = 0;
409205194Sdelphij        state->seek = 0;
410205194Sdelphij        gz_error(state, Z_OK, NULL);
411205194Sdelphij        state->strm.avail_in = 0;
412230837Sdelphij        state->x.pos += offset;
413230837Sdelphij        return state->x.pos;
414205194Sdelphij    }
415205194Sdelphij
416205194Sdelphij    /* calculate skip amount, rewinding if needed for back seek when reading */
417205194Sdelphij    if (offset < 0) {
418205194Sdelphij        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
419205194Sdelphij            return -1;
420230837Sdelphij        offset += state->x.pos;
421205194Sdelphij        if (offset < 0)                     /* before start of file! */
422205194Sdelphij            return -1;
423205194Sdelphij        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
424205194Sdelphij            return -1;
425205194Sdelphij    }
426205194Sdelphij
427205194Sdelphij    /* if reading, skip what's in output buffer (one less gzgetc() check) */
428205194Sdelphij    if (state->mode == GZ_READ) {
429230837Sdelphij        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
430230837Sdelphij            (unsigned)offset : state->x.have;
431230837Sdelphij        state->x.have -= n;
432230837Sdelphij        state->x.next += n;
433230837Sdelphij        state->x.pos += n;
434205194Sdelphij        offset -= n;
435205194Sdelphij    }
436205194Sdelphij
437205194Sdelphij    /* request skip (if not zero) */
438205194Sdelphij    if (offset) {
439205194Sdelphij        state->seek = 1;
440205194Sdelphij        state->skip = offset;
441205194Sdelphij    }
442230837Sdelphij    return state->x.pos + offset;
443205194Sdelphij}
444205194Sdelphij
445205194Sdelphij/* -- see zlib.h -- */
446205194Sdelphijz_off_t ZEXPORT gzseek(file, offset, whence)
447205194Sdelphij    gzFile file;
448205194Sdelphij    z_off_t offset;
449205194Sdelphij    int whence;
450205194Sdelphij{
451205194Sdelphij    z_off64_t ret;
452205194Sdelphij
453205194Sdelphij    ret = gzseek64(file, (z_off64_t)offset, whence);
454205194Sdelphij    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
455205194Sdelphij}
456205194Sdelphij
457205194Sdelphij/* -- see zlib.h -- */
458205194Sdelphijz_off64_t ZEXPORT gztell64(file)
459205194Sdelphij    gzFile file;
460205194Sdelphij{
461205194Sdelphij    gz_statep state;
462205194Sdelphij
463205194Sdelphij    /* get internal structure and check integrity */
464205194Sdelphij    if (file == NULL)
465205194Sdelphij        return -1;
466205194Sdelphij    state = (gz_statep)file;
467205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
468205194Sdelphij        return -1;
469205194Sdelphij
470205194Sdelphij    /* return position */
471230837Sdelphij    return state->x.pos + (state->seek ? state->skip : 0);
472205194Sdelphij}
473205194Sdelphij
474205194Sdelphij/* -- see zlib.h -- */
475205194Sdelphijz_off_t ZEXPORT gztell(file)
476205194Sdelphij    gzFile file;
477205194Sdelphij{
478205194Sdelphij    z_off64_t ret;
479205194Sdelphij
480205194Sdelphij    ret = gztell64(file);
481205194Sdelphij    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
482205194Sdelphij}
483205194Sdelphij
484205194Sdelphij/* -- see zlib.h -- */
485205194Sdelphijz_off64_t ZEXPORT gzoffset64(file)
486205194Sdelphij    gzFile file;
487205194Sdelphij{
488205194Sdelphij    z_off64_t offset;
489205194Sdelphij    gz_statep state;
490205194Sdelphij
491205194Sdelphij    /* get internal structure and check integrity */
492205194Sdelphij    if (file == NULL)
493205194Sdelphij        return -1;
494205194Sdelphij    state = (gz_statep)file;
495205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
496205194Sdelphij        return -1;
497205194Sdelphij
498205194Sdelphij    /* compute and return effective offset in file */
499205194Sdelphij    offset = LSEEK(state->fd, 0, SEEK_CUR);
500205194Sdelphij    if (offset == -1)
501205194Sdelphij        return -1;
502205194Sdelphij    if (state->mode == GZ_READ)             /* reading */
503205194Sdelphij        offset -= state->strm.avail_in;     /* don't count buffered input */
504205194Sdelphij    return offset;
505205194Sdelphij}
506205194Sdelphij
507205194Sdelphij/* -- see zlib.h -- */
508205194Sdelphijz_off_t ZEXPORT gzoffset(file)
509205194Sdelphij    gzFile file;
510205194Sdelphij{
511205194Sdelphij    z_off64_t ret;
512205194Sdelphij
513205194Sdelphij    ret = gzoffset64(file);
514205194Sdelphij    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
515205194Sdelphij}
516205194Sdelphij
517205194Sdelphij/* -- see zlib.h -- */
518205194Sdelphijint ZEXPORT gzeof(file)
519205194Sdelphij    gzFile file;
520205194Sdelphij{
521205194Sdelphij    gz_statep state;
522205194Sdelphij
523205194Sdelphij    /* get internal structure and check integrity */
524205194Sdelphij    if (file == NULL)
525205194Sdelphij        return 0;
526205194Sdelphij    state = (gz_statep)file;
527205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
528205194Sdelphij        return 0;
529205194Sdelphij
530205194Sdelphij    /* return end-of-file state */
531230837Sdelphij    return state->mode == GZ_READ ? state->past : 0;
532205194Sdelphij}
533205194Sdelphij
534205194Sdelphij/* -- see zlib.h -- */
535205194Sdelphijconst char * ZEXPORT gzerror(file, errnum)
536205194Sdelphij    gzFile file;
537205194Sdelphij    int *errnum;
538205194Sdelphij{
539205194Sdelphij    gz_statep state;
540205194Sdelphij
541205194Sdelphij    /* get internal structure and check integrity */
542205194Sdelphij    if (file == NULL)
543205194Sdelphij        return NULL;
544205194Sdelphij    state = (gz_statep)file;
545205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
546205194Sdelphij        return NULL;
547205194Sdelphij
548205194Sdelphij    /* return error information */
549205194Sdelphij    if (errnum != NULL)
550205194Sdelphij        *errnum = state->err;
551250224Sdelphij    return state->err == Z_MEM_ERROR ? "out of memory" :
552250224Sdelphij                                       (state->msg == NULL ? "" : state->msg);
553205194Sdelphij}
554205194Sdelphij
555205194Sdelphij/* -- see zlib.h -- */
556205194Sdelphijvoid ZEXPORT gzclearerr(file)
557205194Sdelphij    gzFile file;
558205194Sdelphij{
559205194Sdelphij    gz_statep state;
560205194Sdelphij
561205194Sdelphij    /* get internal structure and check integrity */
562205194Sdelphij    if (file == NULL)
563205194Sdelphij        return;
564205194Sdelphij    state = (gz_statep)file;
565205194Sdelphij    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
566205194Sdelphij        return;
567205194Sdelphij
568205194Sdelphij    /* clear error and end-of-file */
569230837Sdelphij    if (state->mode == GZ_READ) {
570205194Sdelphij        state->eof = 0;
571230837Sdelphij        state->past = 0;
572230837Sdelphij    }
573205194Sdelphij    gz_error(state, Z_OK, NULL);
574205194Sdelphij}
575205194Sdelphij
576205194Sdelphij/* Create an error message in allocated memory and set state->err and
577205194Sdelphij   state->msg accordingly.  Free any previous error message already there.  Do
578205194Sdelphij   not try to free or allocate space if the error is Z_MEM_ERROR (out of
579205194Sdelphij   memory).  Simply save the error message as a static string.  If there is an
580205194Sdelphij   allocation failure constructing the error message, then convert the error to
581205194Sdelphij   out of memory. */
582206905Sdelphijvoid ZLIB_INTERNAL gz_error(state, err, msg)
583205194Sdelphij    gz_statep state;
584205194Sdelphij    int err;
585205194Sdelphij    const char *msg;
586205194Sdelphij{
587205194Sdelphij    /* free previously allocated message and clear */
588205194Sdelphij    if (state->msg != NULL) {
589205194Sdelphij        if (state->err != Z_MEM_ERROR)
590205194Sdelphij            free(state->msg);
591205194Sdelphij        state->msg = NULL;
592205194Sdelphij    }
593205194Sdelphij
594230837Sdelphij    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
595230837Sdelphij    if (err != Z_OK && err != Z_BUF_ERROR)
596230837Sdelphij        state->x.have = 0;
597230837Sdelphij
598205194Sdelphij    /* set error code, and if no message, then done */
599205194Sdelphij    state->err = err;
600205194Sdelphij    if (msg == NULL)
601205194Sdelphij        return;
602205194Sdelphij
603250224Sdelphij    /* for an out of memory error, return literal string when requested */
604250224Sdelphij    if (err == Z_MEM_ERROR)
605205194Sdelphij        return;
606205194Sdelphij
607205194Sdelphij    /* construct error message with path */
608250224Sdelphij    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
609250224Sdelphij            NULL) {
610205194Sdelphij        state->err = Z_MEM_ERROR;
611205194Sdelphij        return;
612205194Sdelphij    }
613250224Sdelphij#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
614311285Sdelphij    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
615311285Sdelphij                   "%s%s%s", state->path, ": ", msg);
616250224Sdelphij#else
617205194Sdelphij    strcpy(state->msg, state->path);
618205194Sdelphij    strcat(state->msg, ": ");
619205194Sdelphij    strcat(state->msg, msg);
620250224Sdelphij#endif
621205194Sdelphij}
622205194Sdelphij
623205194Sdelphij#ifndef INT_MAX
624205194Sdelphij/* portably return maximum value for an int (when limits.h presumed not
625205194Sdelphij   available) -- we need to do this to cover cases where 2's complement not
626205194Sdelphij   used, since C standard permits 1's complement and sign-bit representations,
627205194Sdelphij   otherwise we could just use ((unsigned)-1) >> 1 */
628206905Sdelphijunsigned ZLIB_INTERNAL gz_intmax()
629205194Sdelphij{
630205194Sdelphij    unsigned p, q;
631205194Sdelphij
632205194Sdelphij    p = 1;
633205194Sdelphij    do {
634205194Sdelphij        q = p;
635205194Sdelphij        p <<= 1;
636205194Sdelphij        p++;
637205194Sdelphij    } while (p > q);
638205194Sdelphij    return q >> 1;
639205194Sdelphij}
640205194Sdelphij#endif
641