xref: /openbsd-src/lib/libz/gzlib.c (revision d62e7792cc782dbe996fdfa0cc89a6ba3ab562cd)
136f395ceStb /* gzlib.c -- zlib functions common to reading and writing gzip files
2d5e7bdb5Stb  * Copyright (C) 2004-2024 Mark Adler
336f395ceStb  * For conditions of distribution and use, see copyright notice in zlib.h
436f395ceStb  */
536f395ceStb 
636f395ceStb #include "gzguts.h"
736f395ceStb 
8*d62e7792Stb #if defined(__DJGPP__)
9312b32e0Stb #  define LSEEK llseek
10*d62e7792Stb #elif defined(_WIN32) && !defined(__BORLANDC__) && !defined(UNDER_CE)
1136f395ceStb #  define LSEEK _lseeki64
12312b32e0Stb #elif defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
1336f395ceStb #  define LSEEK lseek64
1436f395ceStb #else
1536f395ceStb #  define LSEEK lseek
1636f395ceStb #endif
1736f395ceStb 
1836f395ceStb #if defined UNDER_CE
1936f395ceStb 
2036f395ceStb /* Map the Windows error number in ERROR to a locale-dependent error message
2136f395ceStb    string and return a pointer to it.  Typically, the values for ERROR come
2236f395ceStb    from GetLastError.
2336f395ceStb 
2436f395ceStb    The string pointed to shall not be modified by the application, but may be
2536f395ceStb    overwritten by a subsequent call to gz_strwinerror
2636f395ceStb 
2736f395ceStb    The gz_strwinerror function does not change the current setting of
2836f395ceStb    GetLastError. */
gz_strwinerror(DWORD error)29a04ea15dStb char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
3036f395ceStb     static char buf[1024];
3136f395ceStb 
3236f395ceStb     wchar_t *msgbuf;
3336f395ceStb     DWORD lasterr = GetLastError();
3436f395ceStb     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
3536f395ceStb         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
3636f395ceStb         NULL,
3736f395ceStb         error,
3836f395ceStb         0, /* Default language */
3936f395ceStb         (LPVOID)&msgbuf,
4036f395ceStb         0,
4136f395ceStb         NULL);
4236f395ceStb     if (chars != 0) {
4336f395ceStb         /* If there is an \r\n appended, zap it.  */
4436f395ceStb         if (chars >= 2
4536f395ceStb             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
4636f395ceStb             chars -= 2;
4736f395ceStb             msgbuf[chars] = 0;
4836f395ceStb         }
4936f395ceStb 
5036f395ceStb         if (chars > sizeof (buf) - 1) {
5136f395ceStb             chars = sizeof (buf) - 1;
5236f395ceStb             msgbuf[chars] = 0;
5336f395ceStb         }
5436f395ceStb 
55312b32e0Stb         wcstombs(buf, msgbuf, chars + 1);       // assumes buf is big enough
5636f395ceStb         LocalFree(msgbuf);
5736f395ceStb     }
5836f395ceStb     else {
5936f395ceStb         sprintf(buf, "unknown win32 error (%ld)", error);
6036f395ceStb     }
6136f395ceStb 
6236f395ceStb     SetLastError(lasterr);
6336f395ceStb     return buf;
6436f395ceStb }
6536f395ceStb 
6636f395ceStb #endif /* UNDER_CE */
6736f395ceStb 
6836f395ceStb /* Reset gzip file state */
gz_reset(gz_statep state)69a04ea15dStb local void gz_reset(gz_statep state) {
7036f395ceStb     state->x.have = 0;              /* no output data available */
7136f395ceStb     if (state->mode == GZ_READ) {   /* for reading ... */
7236f395ceStb         state->eof = 0;             /* not at end of file */
7336f395ceStb         state->past = 0;            /* have not read past end yet */
7436f395ceStb         state->how = LOOK;          /* look for gzip header */
7536f395ceStb     }
76703d4924Stb     else                            /* for writing ... */
77703d4924Stb         state->reset = 0;           /* no deflateReset pending */
7836f395ceStb     state->seek = 0;                /* no seek request pending */
7936f395ceStb     gz_error(state, Z_OK, NULL);    /* clear error */
8036f395ceStb     state->x.pos = 0;               /* no uncompressed data yet */
8136f395ceStb     state->strm.avail_in = 0;       /* no input data yet */
8236f395ceStb }
8336f395ceStb 
8436f395ceStb /* Open a gzip file either by name or file descriptor. */
gz_open(const void * path,int fd,const char * mode)85a04ea15dStb local gzFile gz_open(const void *path, int fd, const char *mode) {
8636f395ceStb     gz_statep state;
8736f395ceStb     z_size_t len;
8836f395ceStb     int oflag;
8936f395ceStb #ifdef O_CLOEXEC
9036f395ceStb     int cloexec = 0;
9136f395ceStb #endif
9236f395ceStb #ifdef O_EXCL
9336f395ceStb     int exclusive = 0;
9436f395ceStb #endif
9536f395ceStb 
9636f395ceStb     /* check input */
9736f395ceStb     if (path == NULL)
9836f395ceStb         return NULL;
9936f395ceStb 
10036f395ceStb     /* allocate gzFile structure to return */
10136f395ceStb     state = (gz_statep)malloc(sizeof(gz_state));
10236f395ceStb     if (state == NULL)
10336f395ceStb         return NULL;
10436f395ceStb     state->size = 0;            /* no buffers allocated yet */
10536f395ceStb     state->want = GZBUFSIZE;    /* requested buffer size */
10636f395ceStb     state->msg = NULL;          /* no error message yet */
10736f395ceStb 
10836f395ceStb     /* interpret mode */
10936f395ceStb     state->mode = GZ_NONE;
11036f395ceStb     state->level = Z_DEFAULT_COMPRESSION;
11136f395ceStb     state->strategy = Z_DEFAULT_STRATEGY;
11236f395ceStb     state->direct = 0;
11336f395ceStb     while (*mode) {
11436f395ceStb         if (*mode >= '0' && *mode <= '9')
11536f395ceStb             state->level = *mode - '0';
11636f395ceStb         else
11736f395ceStb             switch (*mode) {
11836f395ceStb             case 'r':
11936f395ceStb                 state->mode = GZ_READ;
12036f395ceStb                 break;
12136f395ceStb #ifndef NO_GZCOMPRESS
12236f395ceStb             case 'w':
12336f395ceStb                 state->mode = GZ_WRITE;
12436f395ceStb                 break;
12536f395ceStb             case 'a':
12636f395ceStb                 state->mode = GZ_APPEND;
12736f395ceStb                 break;
12836f395ceStb #endif
12936f395ceStb             case '+':       /* can't read and write at the same time */
13036f395ceStb                 free(state);
13136f395ceStb                 return NULL;
13236f395ceStb             case 'b':       /* ignore -- will request binary anyway */
13336f395ceStb                 break;
13436f395ceStb #ifdef O_CLOEXEC
13536f395ceStb             case 'e':
13636f395ceStb                 cloexec = 1;
13736f395ceStb                 break;
13836f395ceStb #endif
13936f395ceStb #ifdef O_EXCL
14036f395ceStb             case 'x':
14136f395ceStb                 exclusive = 1;
14236f395ceStb                 break;
14336f395ceStb #endif
14436f395ceStb             case 'f':
14536f395ceStb                 state->strategy = Z_FILTERED;
14636f395ceStb                 break;
14736f395ceStb             case 'h':
14836f395ceStb                 state->strategy = Z_HUFFMAN_ONLY;
14936f395ceStb                 break;
15036f395ceStb             case 'R':
15136f395ceStb                 state->strategy = Z_RLE;
15236f395ceStb                 break;
15336f395ceStb             case 'F':
15436f395ceStb                 state->strategy = Z_FIXED;
15536f395ceStb                 break;
15636f395ceStb             case 'T':
15736f395ceStb                 state->direct = 1;
15836f395ceStb                 break;
15936f395ceStb             default:        /* could consider as an error, but just ignore */
16036f395ceStb                 ;
16136f395ceStb             }
16236f395ceStb         mode++;
16336f395ceStb     }
16436f395ceStb 
16536f395ceStb     /* must provide an "r", "w", or "a" */
16636f395ceStb     if (state->mode == GZ_NONE) {
16736f395ceStb         free(state);
16836f395ceStb         return NULL;
16936f395ceStb     }
17036f395ceStb 
17136f395ceStb     /* can't force transparent read */
17236f395ceStb     if (state->mode == GZ_READ) {
17336f395ceStb         if (state->direct) {
17436f395ceStb             free(state);
17536f395ceStb             return NULL;
17636f395ceStb         }
17736f395ceStb         state->direct = 1;      /* for empty file */
17836f395ceStb     }
17936f395ceStb 
18036f395ceStb     /* save the path name for error messages */
18136f395ceStb #ifdef WIDECHAR
182312b32e0Stb     if (fd == -2)
183312b32e0Stb         len = wcstombs(NULL, path, 0);
18436f395ceStb     else
18536f395ceStb #endif
18636f395ceStb         len = strlen((const char *)path);
18736f395ceStb     state->path = (char *)malloc(len + 1);
18836f395ceStb     if (state->path == NULL) {
18936f395ceStb         free(state);
19036f395ceStb         return NULL;
19136f395ceStb     }
19236f395ceStb #ifdef WIDECHAR
193312b32e0Stb     if (fd == -2) {
19436f395ceStb         if (len)
195312b32e0Stb             wcstombs(state->path, path, len + 1);
19636f395ceStb         else
19736f395ceStb             *(state->path) = 0;
198312b32e0Stb     }
19936f395ceStb     else
20036f395ceStb #endif
201312b32e0Stb     {
20236f395ceStb #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
20336f395ceStb         (void)snprintf(state->path, len + 1, "%s", (const char *)path);
20436f395ceStb #else
20536f395ceStb         strcpy(state->path, path);
20636f395ceStb #endif
207312b32e0Stb     }
20836f395ceStb 
20936f395ceStb     /* compute the flags for open() */
21036f395ceStb     oflag =
21136f395ceStb #ifdef O_LARGEFILE
21236f395ceStb         O_LARGEFILE |
21336f395ceStb #endif
21436f395ceStb #ifdef O_BINARY
21536f395ceStb         O_BINARY |
21636f395ceStb #endif
21736f395ceStb #ifdef O_CLOEXEC
21836f395ceStb         (cloexec ? O_CLOEXEC : 0) |
21936f395ceStb #endif
22036f395ceStb         (state->mode == GZ_READ ?
22136f395ceStb          O_RDONLY :
22236f395ceStb          (O_WRONLY | O_CREAT |
22336f395ceStb #ifdef O_EXCL
22436f395ceStb           (exclusive ? O_EXCL : 0) |
22536f395ceStb #endif
22636f395ceStb           (state->mode == GZ_WRITE ?
22736f395ceStb            O_TRUNC :
22836f395ceStb            O_APPEND)));
22936f395ceStb 
23036f395ceStb     /* open the file with the appropriate flags (or just use fd) */
23184324f44Stb     if (fd == -1)
23284324f44Stb         state->fd = open((const char *)path, oflag, 0666);
23336f395ceStb #ifdef WIDECHAR
23484324f44Stb     else if (fd == -2)
235312b32e0Stb         state->fd = _wopen(path, oflag, _S_IREAD | _S_IWRITE);
23636f395ceStb #endif
23784324f44Stb     else
23884324f44Stb         state->fd = fd;
23936f395ceStb     if (state->fd == -1) {
24036f395ceStb         free(state->path);
24136f395ceStb         free(state);
24236f395ceStb         return NULL;
24336f395ceStb     }
24436f395ceStb     if (state->mode == GZ_APPEND) {
24536f395ceStb         LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
24636f395ceStb         state->mode = GZ_WRITE;         /* simplify later checks */
24736f395ceStb     }
24836f395ceStb 
24936f395ceStb     /* save the current position for rewinding (only if reading) */
25036f395ceStb     if (state->mode == GZ_READ) {
25136f395ceStb         state->start = LSEEK(state->fd, 0, SEEK_CUR);
25236f395ceStb         if (state->start == -1) state->start = 0;
25336f395ceStb     }
25436f395ceStb 
25536f395ceStb     /* initialize stream */
25636f395ceStb     gz_reset(state);
25736f395ceStb 
25836f395ceStb     /* return stream */
25936f395ceStb     return (gzFile)state;
26036f395ceStb }
26136f395ceStb 
26236f395ceStb /* -- see zlib.h -- */
gzopen(const char * path,const char * mode)263a04ea15dStb gzFile ZEXPORT gzopen(const char *path, const char *mode) {
26436f395ceStb     return gz_open(path, -1, mode);
26536f395ceStb }
26636f395ceStb 
26736f395ceStb /* -- see zlib.h -- */
gzopen64(const char * path,const char * mode)268a04ea15dStb gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
26936f395ceStb     return gz_open(path, -1, mode);
27036f395ceStb }
27136f395ceStb 
27236f395ceStb /* -- see zlib.h -- */
gzdopen(int fd,const char * mode)273a04ea15dStb gzFile ZEXPORT gzdopen(int fd, const char *mode) {
27436f395ceStb     char *path;         /* identifier for error messages */
27536f395ceStb     gzFile gz;
27636f395ceStb 
27736f395ceStb     if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
27836f395ceStb         return NULL;
27936f395ceStb #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
28036f395ceStb     (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
28136f395ceStb #else
28236f395ceStb     sprintf(path, "<fd:%d>", fd);   /* for debugging */
28336f395ceStb #endif
28436f395ceStb     gz = gz_open(path, fd, mode);
28536f395ceStb     free(path);
28636f395ceStb     return gz;
28736f395ceStb }
28836f395ceStb 
28936f395ceStb /* -- see zlib.h -- */
29036f395ceStb #ifdef WIDECHAR
gzopen_w(const wchar_t * path,const char * mode)291a04ea15dStb gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
29236f395ceStb     return gz_open(path, -2, mode);
29336f395ceStb }
29436f395ceStb #endif
29536f395ceStb 
29636f395ceStb /* -- see zlib.h -- */
gzbuffer(gzFile file,unsigned size)297a04ea15dStb int ZEXPORT gzbuffer(gzFile file, unsigned size) {
29836f395ceStb     gz_statep state;
29936f395ceStb 
30036f395ceStb     /* get internal structure and check integrity */
30136f395ceStb     if (file == NULL)
30236f395ceStb         return -1;
30336f395ceStb     state = (gz_statep)file;
30436f395ceStb     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
30536f395ceStb         return -1;
30636f395ceStb 
30736f395ceStb     /* make sure we haven't already allocated memory */
30836f395ceStb     if (state->size != 0)
30936f395ceStb         return -1;
31036f395ceStb 
31136f395ceStb     /* check and set requested size */
31236f395ceStb     if ((size << 1) < size)
31336f395ceStb         return -1;              /* need to be able to double it */
314cb4f93b0Stb     if (size < 8)
315cb4f93b0Stb         size = 8;               /* needed to behave well with flushing */
31636f395ceStb     state->want = size;
31736f395ceStb     return 0;
31836f395ceStb }
31936f395ceStb 
32036f395ceStb /* -- see zlib.h -- */
gzrewind(gzFile file)321a04ea15dStb int ZEXPORT gzrewind(gzFile file) {
32236f395ceStb     gz_statep state;
32336f395ceStb 
32436f395ceStb     /* get internal structure */
32536f395ceStb     if (file == NULL)
32636f395ceStb         return -1;
32736f395ceStb     state = (gz_statep)file;
32836f395ceStb 
32936f395ceStb     /* check that we're reading and that there's no error */
33036f395ceStb     if (state->mode != GZ_READ ||
33136f395ceStb             (state->err != Z_OK && state->err != Z_BUF_ERROR))
33236f395ceStb         return -1;
33336f395ceStb 
33436f395ceStb     /* back up and start over */
33536f395ceStb     if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
33636f395ceStb         return -1;
33736f395ceStb     gz_reset(state);
33836f395ceStb     return 0;
33936f395ceStb }
34036f395ceStb 
34136f395ceStb /* -- see zlib.h -- */
gzseek64(gzFile file,z_off64_t offset,int whence)342a04ea15dStb z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
34336f395ceStb     unsigned n;
34436f395ceStb     z_off64_t ret;
34536f395ceStb     gz_statep state;
34636f395ceStb 
34736f395ceStb     /* get internal structure and check integrity */
34836f395ceStb     if (file == NULL)
34936f395ceStb         return -1;
35036f395ceStb     state = (gz_statep)file;
35136f395ceStb     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
35236f395ceStb         return -1;
35336f395ceStb 
35436f395ceStb     /* check that there's no error */
35536f395ceStb     if (state->err != Z_OK && state->err != Z_BUF_ERROR)
35636f395ceStb         return -1;
35736f395ceStb 
35836f395ceStb     /* can only seek from start or relative to current position */
35936f395ceStb     if (whence != SEEK_SET && whence != SEEK_CUR)
36036f395ceStb         return -1;
36136f395ceStb 
36236f395ceStb     /* normalize offset to a SEEK_CUR specification */
36336f395ceStb     if (whence == SEEK_SET)
36436f395ceStb         offset -= state->x.pos;
36536f395ceStb     else if (state->seek)
36636f395ceStb         offset += state->skip;
36736f395ceStb     state->seek = 0;
36836f395ceStb 
36936f395ceStb     /* if within raw area while reading, just go there */
37036f395ceStb     if (state->mode == GZ_READ && state->how == COPY &&
37136f395ceStb             state->x.pos + offset >= 0) {
372703d4924Stb         ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
37336f395ceStb         if (ret == -1)
37436f395ceStb             return -1;
37536f395ceStb         state->x.have = 0;
37636f395ceStb         state->eof = 0;
37736f395ceStb         state->past = 0;
37836f395ceStb         state->seek = 0;
37936f395ceStb         gz_error(state, Z_OK, NULL);
38036f395ceStb         state->strm.avail_in = 0;
38136f395ceStb         state->x.pos += offset;
38236f395ceStb         return state->x.pos;
38336f395ceStb     }
38436f395ceStb 
38536f395ceStb     /* calculate skip amount, rewinding if needed for back seek when reading */
38636f395ceStb     if (offset < 0) {
38736f395ceStb         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
38836f395ceStb             return -1;
38936f395ceStb         offset += state->x.pos;
39036f395ceStb         if (offset < 0)                     /* before start of file! */
39136f395ceStb             return -1;
39236f395ceStb         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
39336f395ceStb             return -1;
39436f395ceStb     }
39536f395ceStb 
39636f395ceStb     /* if reading, skip what's in output buffer (one less gzgetc() check) */
39736f395ceStb     if (state->mode == GZ_READ) {
39836f395ceStb         n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
39936f395ceStb             (unsigned)offset : state->x.have;
40036f395ceStb         state->x.have -= n;
40136f395ceStb         state->x.next += n;
40236f395ceStb         state->x.pos += n;
40336f395ceStb         offset -= n;
40436f395ceStb     }
40536f395ceStb 
40636f395ceStb     /* request skip (if not zero) */
40736f395ceStb     if (offset) {
40836f395ceStb         state->seek = 1;
40936f395ceStb         state->skip = offset;
41036f395ceStb     }
41136f395ceStb     return state->x.pos + offset;
41236f395ceStb }
41336f395ceStb 
41436f395ceStb /* -- see zlib.h -- */
gzseek(gzFile file,z_off_t offset,int whence)415a04ea15dStb z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
41636f395ceStb     z_off64_t ret;
41736f395ceStb 
41836f395ceStb     ret = gzseek64(file, (z_off64_t)offset, whence);
41936f395ceStb     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
42036f395ceStb }
42136f395ceStb 
42236f395ceStb /* -- see zlib.h -- */
gztell64(gzFile file)423a04ea15dStb z_off64_t ZEXPORT gztell64(gzFile file) {
42436f395ceStb     gz_statep state;
42536f395ceStb 
42636f395ceStb     /* get internal structure and check integrity */
42736f395ceStb     if (file == NULL)
42836f395ceStb         return -1;
42936f395ceStb     state = (gz_statep)file;
43036f395ceStb     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
43136f395ceStb         return -1;
43236f395ceStb 
43336f395ceStb     /* return position */
43436f395ceStb     return state->x.pos + (state->seek ? state->skip : 0);
43536f395ceStb }
43636f395ceStb 
43736f395ceStb /* -- see zlib.h -- */
gztell(gzFile file)438a04ea15dStb z_off_t ZEXPORT gztell(gzFile file) {
43936f395ceStb     z_off64_t ret;
44036f395ceStb 
44136f395ceStb     ret = gztell64(file);
44236f395ceStb     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
44336f395ceStb }
44436f395ceStb 
44536f395ceStb /* -- see zlib.h -- */
gzoffset64(gzFile file)446a04ea15dStb z_off64_t ZEXPORT gzoffset64(gzFile file) {
44736f395ceStb     z_off64_t offset;
44836f395ceStb     gz_statep state;
44936f395ceStb 
45036f395ceStb     /* get internal structure and check integrity */
45136f395ceStb     if (file == NULL)
45236f395ceStb         return -1;
45336f395ceStb     state = (gz_statep)file;
45436f395ceStb     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
45536f395ceStb         return -1;
45636f395ceStb 
45736f395ceStb     /* compute and return effective offset in file */
45836f395ceStb     offset = LSEEK(state->fd, 0, SEEK_CUR);
45936f395ceStb     if (offset == -1)
46036f395ceStb         return -1;
46136f395ceStb     if (state->mode == GZ_READ)             /* reading */
46236f395ceStb         offset -= state->strm.avail_in;     /* don't count buffered input */
46336f395ceStb     return offset;
46436f395ceStb }
46536f395ceStb 
46636f395ceStb /* -- see zlib.h -- */
gzoffset(gzFile file)467a04ea15dStb z_off_t ZEXPORT gzoffset(gzFile file) {
46836f395ceStb     z_off64_t ret;
46936f395ceStb 
47036f395ceStb     ret = gzoffset64(file);
47136f395ceStb     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
47236f395ceStb }
47336f395ceStb 
47436f395ceStb /* -- see zlib.h -- */
gzeof(gzFile file)475a04ea15dStb int ZEXPORT gzeof(gzFile file) {
47636f395ceStb     gz_statep state;
47736f395ceStb 
47836f395ceStb     /* get internal structure and check integrity */
47936f395ceStb     if (file == NULL)
48036f395ceStb         return 0;
48136f395ceStb     state = (gz_statep)file;
48236f395ceStb     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
48336f395ceStb         return 0;
48436f395ceStb 
48536f395ceStb     /* return end-of-file state */
48636f395ceStb     return state->mode == GZ_READ ? state->past : 0;
48736f395ceStb }
48836f395ceStb 
48936f395ceStb /* -- see zlib.h -- */
gzerror(gzFile file,int * errnum)490a04ea15dStb const char * ZEXPORT gzerror(gzFile file, int *errnum) {
49136f395ceStb     gz_statep state;
49236f395ceStb 
49336f395ceStb     /* get internal structure and check integrity */
49436f395ceStb     if (file == NULL)
49536f395ceStb         return NULL;
49636f395ceStb     state = (gz_statep)file;
49736f395ceStb     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
49836f395ceStb         return NULL;
49936f395ceStb 
50036f395ceStb     /* return error information */
50136f395ceStb     if (errnum != NULL)
50236f395ceStb         *errnum = state->err;
50336f395ceStb     return state->err == Z_MEM_ERROR ? "out of memory" :
50436f395ceStb                                        (state->msg == NULL ? "" : state->msg);
50536f395ceStb }
50636f395ceStb 
50736f395ceStb /* -- see zlib.h -- */
gzclearerr(gzFile file)508a04ea15dStb void ZEXPORT gzclearerr(gzFile file) {
50936f395ceStb     gz_statep state;
51036f395ceStb 
51136f395ceStb     /* get internal structure and check integrity */
51236f395ceStb     if (file == NULL)
51336f395ceStb         return;
51436f395ceStb     state = (gz_statep)file;
51536f395ceStb     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
51636f395ceStb         return;
51736f395ceStb 
51836f395ceStb     /* clear error and end-of-file */
51936f395ceStb     if (state->mode == GZ_READ) {
52036f395ceStb         state->eof = 0;
52136f395ceStb         state->past = 0;
52236f395ceStb     }
52336f395ceStb     gz_error(state, Z_OK, NULL);
52436f395ceStb }
52536f395ceStb 
52636f395ceStb /* Create an error message in allocated memory and set state->err and
52736f395ceStb    state->msg accordingly.  Free any previous error message already there.  Do
52836f395ceStb    not try to free or allocate space if the error is Z_MEM_ERROR (out of
52936f395ceStb    memory).  Simply save the error message as a static string.  If there is an
53036f395ceStb    allocation failure constructing the error message, then convert the error to
53136f395ceStb    out of memory. */
gz_error(gz_statep state,int err,const char * msg)532a04ea15dStb void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
53336f395ceStb     /* free previously allocated message and clear */
53436f395ceStb     if (state->msg != NULL) {
53536f395ceStb         if (state->err != Z_MEM_ERROR)
53636f395ceStb             free(state->msg);
53736f395ceStb         state->msg = NULL;
53836f395ceStb     }
53936f395ceStb 
54036f395ceStb     /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
54136f395ceStb     if (err != Z_OK && err != Z_BUF_ERROR)
54236f395ceStb         state->x.have = 0;
54336f395ceStb 
54436f395ceStb     /* set error code, and if no message, then done */
54536f395ceStb     state->err = err;
54636f395ceStb     if (msg == NULL)
54736f395ceStb         return;
54836f395ceStb 
54936f395ceStb     /* for an out of memory error, return literal string when requested */
55036f395ceStb     if (err == Z_MEM_ERROR)
55136f395ceStb         return;
55236f395ceStb 
55336f395ceStb     /* construct error message with path */
55436f395ceStb     if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
55536f395ceStb             NULL) {
55636f395ceStb         state->err = Z_MEM_ERROR;
55736f395ceStb         return;
55836f395ceStb     }
55936f395ceStb #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
56036f395ceStb     (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
56136f395ceStb                    "%s%s%s", state->path, ": ", msg);
56236f395ceStb #else
56336f395ceStb     strcpy(state->msg, state->path);
56436f395ceStb     strcat(state->msg, ": ");
56536f395ceStb     strcat(state->msg, msg);
56636f395ceStb #endif
56736f395ceStb }
56836f395ceStb 
56936f395ceStb /* portably return maximum value for an int (when limits.h presumed not
57036f395ceStb    available) -- we need to do this to cover cases where 2's complement not
57136f395ceStb    used, since C standard permits 1's complement and sign-bit representations,
57236f395ceStb    otherwise we could just use ((unsigned)-1) >> 1 */
gz_intmax(void)573a04ea15dStb unsigned ZLIB_INTERNAL gz_intmax(void) {
574f5252e2dStb #ifdef INT_MAX
575f5252e2dStb     return INT_MAX;
576f5252e2dStb #else
577f5252e2dStb     unsigned p = 1, q;
57836f395ceStb     do {
57936f395ceStb         q = p;
58036f395ceStb         p <<= 1;
58136f395ceStb         p++;
58236f395ceStb     } while (p > q);
58336f395ceStb     return q >> 1;
58436f395ceStb #endif
585f5252e2dStb }
586