xref: /freebsd/sys/contrib/zstd/zlibWrapper/gzlib.c (revision 9cbefe25d46756f342c7dd3d174d2d1103808f21)
10c16b537SWarner Losh /* gzlib.c contains minimal changes required to be compiled with zlibWrapper:
20c16b537SWarner Losh  * - gz_statep was converted to union to work with -Wstrict-aliasing=1      */
30c16b537SWarner Losh 
40c16b537SWarner Losh /* gzlib.c -- zlib functions common to reading and writing gzip files
50c16b537SWarner Losh  * Copyright (C) 2004-2017 Mark Adler
60c16b537SWarner Losh  * For conditions of distribution and use, see http://www.zlib.net/zlib_license.html
70c16b537SWarner Losh  */
80c16b537SWarner Losh 
90c16b537SWarner Losh #include "gzguts.h"
100c16b537SWarner Losh 
110c16b537SWarner Losh #if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__)
120c16b537SWarner Losh #  define LSEEK _lseeki64
130c16b537SWarner Losh #else
140c16b537SWarner Losh #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
150c16b537SWarner Losh #  define LSEEK lseek64
160c16b537SWarner Losh #else
170c16b537SWarner Losh #  define LSEEK lseek
180c16b537SWarner Losh #endif
190c16b537SWarner Losh #endif
200c16b537SWarner Losh 
210c16b537SWarner Losh /* Local functions */
220c16b537SWarner Losh local void gz_reset OF((gz_statep));
230c16b537SWarner Losh local gzFile gz_open OF((const void *, int, const char *));
240c16b537SWarner Losh 
250c16b537SWarner Losh #if defined UNDER_CE
260c16b537SWarner Losh 
270c16b537SWarner Losh /* Map the Windows error number in ERROR to a locale-dependent error message
280c16b537SWarner Losh    string and return a pointer to it.  Typically, the values for ERROR come
290c16b537SWarner Losh    from GetLastError.
300c16b537SWarner Losh 
310c16b537SWarner Losh    The string pointed to shall not be modified by the application, but may be
320c16b537SWarner Losh    overwritten by a subsequent call to gz_strwinerror
330c16b537SWarner Losh 
340c16b537SWarner Losh    The gz_strwinerror function does not change the current setting of
350c16b537SWarner Losh    GetLastError. */
gz_strwinerror(error)360c16b537SWarner Losh char ZLIB_INTERNAL *gz_strwinerror (error)
370c16b537SWarner Losh      DWORD error;
380c16b537SWarner Losh {
390c16b537SWarner Losh     static char buf[1024];
400c16b537SWarner Losh 
410c16b537SWarner Losh     wchar_t *msgbuf;
420c16b537SWarner Losh     DWORD lasterr = GetLastError();
430c16b537SWarner Losh     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
440c16b537SWarner Losh         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
450c16b537SWarner Losh         NULL,
460c16b537SWarner Losh         error,
470c16b537SWarner Losh         0, /* Default language */
480c16b537SWarner Losh         (LPVOID)&msgbuf,
490c16b537SWarner Losh         0,
500c16b537SWarner Losh         NULL);
510c16b537SWarner Losh     if (chars != 0) {
520c16b537SWarner Losh         /* If there is an \r\n appended, zap it.  */
530c16b537SWarner Losh         if (chars >= 2
540c16b537SWarner Losh             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
550c16b537SWarner Losh             chars -= 2;
560c16b537SWarner Losh             msgbuf[chars] = 0;
570c16b537SWarner Losh         }
580c16b537SWarner Losh 
590c16b537SWarner Losh         if (chars > sizeof (buf) - 1) {
600c16b537SWarner Losh             chars = sizeof (buf) - 1;
610c16b537SWarner Losh             msgbuf[chars] = 0;
620c16b537SWarner Losh         }
630c16b537SWarner Losh 
640c16b537SWarner Losh         wcstombs(buf, msgbuf, chars + 1);
650c16b537SWarner Losh         LocalFree(msgbuf);
660c16b537SWarner Losh     }
670c16b537SWarner Losh     else {
680c16b537SWarner Losh         sprintf(buf, "unknown win32 error (%ld)", error);
690c16b537SWarner Losh     }
700c16b537SWarner Losh 
710c16b537SWarner Losh     SetLastError(lasterr);
720c16b537SWarner Losh     return buf;
730c16b537SWarner Losh }
740c16b537SWarner Losh 
750c16b537SWarner Losh #endif /* UNDER_CE */
760c16b537SWarner Losh 
770c16b537SWarner Losh /* Reset gzip file state */
gz_reset(state)780c16b537SWarner Losh local void gz_reset(state)
790c16b537SWarner Losh     gz_statep state;
800c16b537SWarner Losh {
810c16b537SWarner Losh     state.state->x.have = 0;              /* no output data available */
820c16b537SWarner Losh     if (state.state->mode == GZ_READ) {   /* for reading ... */
830c16b537SWarner Losh         state.state->eof = 0;             /* not at end of file */
840c16b537SWarner Losh         state.state->past = 0;            /* have not read past end yet */
850c16b537SWarner Losh         state.state->how = LOOK;          /* look for gzip header */
860c16b537SWarner Losh     }
870c16b537SWarner Losh     state.state->seek = 0;                /* no seek request pending */
880c16b537SWarner Losh     gz_error(state, Z_OK, NULL);    /* clear error */
890c16b537SWarner Losh     state.state->x.pos = 0;               /* no uncompressed data yet */
900c16b537SWarner Losh     state.state->strm.avail_in = 0;       /* no input data yet */
910c16b537SWarner Losh }
920c16b537SWarner Losh 
930c16b537SWarner Losh /* Open a gzip file either by name or file descriptor. */
gz_open(path,fd,mode)940c16b537SWarner Losh local gzFile gz_open(path, fd, mode)
950c16b537SWarner Losh     const void *path;
960c16b537SWarner Losh     int fd;
970c16b537SWarner Losh     const char *mode;
980c16b537SWarner Losh {
990c16b537SWarner Losh     gz_statep state;
1000c16b537SWarner Losh     z_size_t len;
1010c16b537SWarner Losh     int oflag;
1020c16b537SWarner Losh #ifdef O_CLOEXEC
1030c16b537SWarner Losh     int cloexec = 0;
1040c16b537SWarner Losh #endif
1050c16b537SWarner Losh #ifdef O_EXCL
1060c16b537SWarner Losh     int exclusive = 0;
1070c16b537SWarner Losh #endif
1080c16b537SWarner Losh 
1090c16b537SWarner Losh     /* check input */
1100c16b537SWarner Losh     if (path == NULL)
1110c16b537SWarner Losh         return NULL;
1120c16b537SWarner Losh 
1130c16b537SWarner Losh     /* allocate gzFile structure to return */
1140f743729SConrad Meyer     state.state = (gz_state*)malloc(sizeof(gz_state));
1150c16b537SWarner Losh     if (state.state == NULL)
1160c16b537SWarner Losh         return NULL;
1170c16b537SWarner Losh     state.state->size = 0;            /* no buffers allocated yet */
1180c16b537SWarner Losh     state.state->want = GZBUFSIZE;    /* requested buffer size */
1190c16b537SWarner Losh     state.state->msg = NULL;          /* no error message yet */
1200c16b537SWarner Losh 
1210c16b537SWarner Losh     /* interpret mode */
1220c16b537SWarner Losh     state.state->mode = GZ_NONE;
1230c16b537SWarner Losh     state.state->level = Z_DEFAULT_COMPRESSION;
1240c16b537SWarner Losh     state.state->strategy = Z_DEFAULT_STRATEGY;
1250c16b537SWarner Losh     state.state->direct = 0;
1260c16b537SWarner Losh     while (*mode) {
1270c16b537SWarner Losh         if (*mode >= '0' && *mode <= '9')
1280c16b537SWarner Losh             state.state->level = *mode - '0';
1290c16b537SWarner Losh         else
1300c16b537SWarner Losh             switch (*mode) {
1310c16b537SWarner Losh             case 'r':
1320c16b537SWarner Losh                 state.state->mode = GZ_READ;
1330c16b537SWarner Losh                 break;
1340c16b537SWarner Losh #ifndef NO_GZCOMPRESS
1350c16b537SWarner Losh             case 'w':
1360c16b537SWarner Losh                 state.state->mode = GZ_WRITE;
1370c16b537SWarner Losh                 break;
1380c16b537SWarner Losh             case 'a':
1390c16b537SWarner Losh                 state.state->mode = GZ_APPEND;
1400c16b537SWarner Losh                 break;
1410c16b537SWarner Losh #endif
1420c16b537SWarner Losh             case '+':       /* can't read and write at the same time */
1430c16b537SWarner Losh                 free(state.state);
1440c16b537SWarner Losh                 return NULL;
1450c16b537SWarner Losh             case 'b':       /* ignore -- will request binary anyway */
1460c16b537SWarner Losh                 break;
1470c16b537SWarner Losh #ifdef O_CLOEXEC
1480c16b537SWarner Losh             case 'e':
1490c16b537SWarner Losh                 cloexec = 1;
1500c16b537SWarner Losh                 break;
1510c16b537SWarner Losh #endif
1520c16b537SWarner Losh #ifdef O_EXCL
1530c16b537SWarner Losh             case 'x':
1540c16b537SWarner Losh                 exclusive = 1;
1550c16b537SWarner Losh                 break;
1560c16b537SWarner Losh #endif
1570c16b537SWarner Losh             case 'f':
1580c16b537SWarner Losh                 state.state->strategy = Z_FILTERED;
1590c16b537SWarner Losh                 break;
1600c16b537SWarner Losh             case 'h':
1610c16b537SWarner Losh                 state.state->strategy = Z_HUFFMAN_ONLY;
1620c16b537SWarner Losh                 break;
1630c16b537SWarner Losh             case 'R':
1640c16b537SWarner Losh                 state.state->strategy = Z_RLE;
1650c16b537SWarner Losh                 break;
1660c16b537SWarner Losh             case 'F':
1670c16b537SWarner Losh                 state.state->strategy = Z_FIXED;
1680c16b537SWarner Losh                 break;
1690c16b537SWarner Losh             case 'T':
1700c16b537SWarner Losh                 state.state->direct = 1;
1710c16b537SWarner Losh                 break;
1720c16b537SWarner Losh             default:        /* could consider as an error, but just ignore */
1730c16b537SWarner Losh                 ;
1740c16b537SWarner Losh             }
1750c16b537SWarner Losh         mode++;
1760c16b537SWarner Losh     }
1770c16b537SWarner Losh 
1780c16b537SWarner Losh     /* must provide an "r", "w", or "a" */
1790c16b537SWarner Losh     if (state.state->mode == GZ_NONE) {
1800c16b537SWarner Losh         free(state.state);
1810c16b537SWarner Losh         return NULL;
1820c16b537SWarner Losh     }
1830c16b537SWarner Losh 
1840c16b537SWarner Losh     /* can't force transparent read */
1850c16b537SWarner Losh     if (state.state->mode == GZ_READ) {
1860c16b537SWarner Losh         if (state.state->direct) {
1870c16b537SWarner Losh             free(state.state);
1880c16b537SWarner Losh             return NULL;
1890c16b537SWarner Losh         }
1900c16b537SWarner Losh         state.state->direct = 1;      /* for empty file */
1910c16b537SWarner Losh     }
1920c16b537SWarner Losh 
1930c16b537SWarner Losh     /* save the path name for error messages */
1940c16b537SWarner Losh #ifdef WIDECHAR
1950c16b537SWarner Losh     if (fd == -2) {
1960c16b537SWarner Losh         len = wcstombs(NULL, path, 0);
1970c16b537SWarner Losh         if (len == (z_size_t)-1)
1980c16b537SWarner Losh             len = 0;
1990c16b537SWarner Losh     }
2000c16b537SWarner Losh     else
2010c16b537SWarner Losh #endif
2020c16b537SWarner Losh         len = strlen((const char *)path);
2030c16b537SWarner Losh     state.state->path = (char *)malloc(len + 1);
2040c16b537SWarner Losh     if (state.state->path == NULL) {
2050c16b537SWarner Losh         free(state.state);
2060c16b537SWarner Losh         return NULL;
2070c16b537SWarner Losh     }
2080c16b537SWarner Losh #ifdef WIDECHAR
2090c16b537SWarner Losh     if (fd == -2)
2100c16b537SWarner Losh         if (len)
2110c16b537SWarner Losh             wcstombs(state.state->path, path, len + 1);
2120c16b537SWarner Losh         else
2130c16b537SWarner Losh             *(state.state->path) = 0;
2140c16b537SWarner Losh     else
2150c16b537SWarner Losh #endif
2160c16b537SWarner Losh #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
2170c16b537SWarner Losh         (void)snprintf(state.state->path, len + 1, "%s", (const char *)path);
2180c16b537SWarner Losh #else
219*9cbefe25SConrad Meyer         strcpy(state.state->path, (const char*)path);
2200c16b537SWarner Losh #endif
2210c16b537SWarner Losh 
2220c16b537SWarner Losh     /* compute the flags for open() */
2230c16b537SWarner Losh     oflag =
2240c16b537SWarner Losh #ifdef O_LARGEFILE
2250c16b537SWarner Losh         O_LARGEFILE |
2260c16b537SWarner Losh #endif
2270c16b537SWarner Losh #ifdef O_BINARY
2280c16b537SWarner Losh         O_BINARY |
2290c16b537SWarner Losh #endif
2300c16b537SWarner Losh #ifdef O_CLOEXEC
2310c16b537SWarner Losh         (cloexec ? O_CLOEXEC : 0) |
2320c16b537SWarner Losh #endif
2330c16b537SWarner Losh         (state.state->mode == GZ_READ ?
2340c16b537SWarner Losh          O_RDONLY :
2350c16b537SWarner Losh          (O_WRONLY | O_CREAT |
2360c16b537SWarner Losh #ifdef O_EXCL
2370c16b537SWarner Losh           (exclusive ? O_EXCL : 0) |
2380c16b537SWarner Losh #endif
2390c16b537SWarner Losh           (state.state->mode == GZ_WRITE ?
2400c16b537SWarner Losh            O_TRUNC :
2410c16b537SWarner Losh            O_APPEND)));
2420c16b537SWarner Losh 
2430c16b537SWarner Losh     /* open the file with the appropriate flags (or just use fd) */
2440c16b537SWarner Losh     state.state->fd = fd > -1 ? fd : (
2450c16b537SWarner Losh #ifdef WIDECHAR
2460c16b537SWarner Losh         fd == -2 ? _wopen(path, oflag, 0666) :
2470c16b537SWarner Losh #endif
2480c16b537SWarner Losh         open((const char *)path, oflag, 0666));
2490c16b537SWarner Losh     if (state.state->fd == -1) {
2500c16b537SWarner Losh         free(state.state->path);
2510c16b537SWarner Losh         free(state.state);
2520c16b537SWarner Losh         return NULL;
2530c16b537SWarner Losh     }
2540c16b537SWarner Losh     if (state.state->mode == GZ_APPEND) {
2550c16b537SWarner Losh         LSEEK(state.state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
2560c16b537SWarner Losh         state.state->mode = GZ_WRITE;         /* simplify later checks */
2570c16b537SWarner Losh     }
2580c16b537SWarner Losh 
2590c16b537SWarner Losh     /* save the current position for rewinding (only if reading) */
2600c16b537SWarner Losh     if (state.state->mode == GZ_READ) {
2610c16b537SWarner Losh         state.state->start = LSEEK(state.state->fd, 0, SEEK_CUR);
2620c16b537SWarner Losh         if (state.state->start == -1) state.state->start = 0;
2630c16b537SWarner Losh     }
2640c16b537SWarner Losh 
2650c16b537SWarner Losh     /* initialize stream */
2660c16b537SWarner Losh     gz_reset(state);
2670c16b537SWarner Losh 
2680c16b537SWarner Losh     /* return stream */
2690f743729SConrad Meyer     return state.file;
2700c16b537SWarner Losh }
2710c16b537SWarner Losh 
2720c16b537SWarner Losh /* -- see zlib.h -- */
gzopen(path,mode)2730c16b537SWarner Losh gzFile ZEXPORT gzopen(path, mode)
2740c16b537SWarner Losh     const char *path;
2750c16b537SWarner Losh     const char *mode;
2760c16b537SWarner Losh {
2770c16b537SWarner Losh     return gz_open(path, -1, mode);
2780c16b537SWarner Losh }
2790c16b537SWarner Losh 
2800c16b537SWarner Losh /* -- see zlib.h -- */
gzopen64(path,mode)2810c16b537SWarner Losh gzFile ZEXPORT gzopen64(path, mode)
2820c16b537SWarner Losh     const char *path;
2830c16b537SWarner Losh     const char *mode;
2840c16b537SWarner Losh {
2850c16b537SWarner Losh     return gz_open(path, -1, mode);
2860c16b537SWarner Losh }
2870c16b537SWarner Losh 
2880c16b537SWarner Losh /* -- see zlib.h -- */
gzdopen(fd,mode)2890c16b537SWarner Losh gzFile ZEXPORT gzdopen(fd, mode)
2900c16b537SWarner Losh     int fd;
2910c16b537SWarner Losh     const char *mode;
2920c16b537SWarner Losh {
2930c16b537SWarner Losh     char *path;         /* identifier for error messages */
2940c16b537SWarner Losh     gzFile gz;
2950c16b537SWarner Losh 
2960c16b537SWarner Losh     if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
2970c16b537SWarner Losh         return NULL;
2980c16b537SWarner Losh #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
2990c16b537SWarner Losh     (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
3000c16b537SWarner Losh #else
3010c16b537SWarner Losh     sprintf(path, "<fd:%d>", fd);   /* for debugging */
3020c16b537SWarner Losh #endif
3030c16b537SWarner Losh     gz = gz_open(path, fd, mode);
3040c16b537SWarner Losh     free(path);
3050c16b537SWarner Losh     return gz;
3060c16b537SWarner Losh }
3070c16b537SWarner Losh 
3080c16b537SWarner Losh /* -- see zlib.h -- */
3090c16b537SWarner Losh #ifdef WIDECHAR
gzopen_w(path,mode)3100c16b537SWarner Losh gzFile ZEXPORT gzopen_w(path, mode)
3110c16b537SWarner Losh     const wchar_t *path;
3120c16b537SWarner Losh     const char *mode;
3130c16b537SWarner Losh {
3140c16b537SWarner Losh     return gz_open(path, -2, mode);
3150c16b537SWarner Losh }
3160c16b537SWarner Losh #endif
3170c16b537SWarner Losh 
3180c16b537SWarner Losh /* -- see zlib.h -- */
gzbuffer(file,size)3190c16b537SWarner Losh int ZEXPORT gzbuffer(file, size)
3200c16b537SWarner Losh     gzFile file;
3210c16b537SWarner Losh     unsigned size;
3220c16b537SWarner Losh {
3230c16b537SWarner Losh     gz_statep state;
3240c16b537SWarner Losh 
3250c16b537SWarner Losh     /* get internal structure and check integrity */
3260c16b537SWarner Losh     if (file == NULL)
3270c16b537SWarner Losh         return -1;
328*9cbefe25SConrad Meyer     state.file = file;
3290c16b537SWarner Losh     if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)
3300c16b537SWarner Losh         return -1;
3310c16b537SWarner Losh 
3320c16b537SWarner Losh     /* make sure we haven't already allocated memory */
3330c16b537SWarner Losh     if (state.state->size != 0)
3340c16b537SWarner Losh         return -1;
3350c16b537SWarner Losh 
3360c16b537SWarner Losh     /* check and set requested size */
3370c16b537SWarner Losh     if ((size << 1) < size)
3380c16b537SWarner Losh         return -1;              /* need to be able to double it */
3390c16b537SWarner Losh     if (size < 2)
3400c16b537SWarner Losh         size = 2;               /* need two bytes to check magic header */
3410c16b537SWarner Losh     state.state->want = size;
3420c16b537SWarner Losh     return 0;
3430c16b537SWarner Losh }
3440c16b537SWarner Losh 
3450c16b537SWarner Losh /* -- see zlib.h -- */
gzrewind(file)3460c16b537SWarner Losh int ZEXPORT gzrewind(file)
3470c16b537SWarner Losh     gzFile file;
3480c16b537SWarner Losh {
3490c16b537SWarner Losh     gz_statep state;
3500c16b537SWarner Losh 
3510c16b537SWarner Losh     /* get internal structure */
3520c16b537SWarner Losh     if (file == NULL)
3530c16b537SWarner Losh         return -1;
354*9cbefe25SConrad Meyer     state.file = file;
3550c16b537SWarner Losh 
3560c16b537SWarner Losh     /* check that we're reading and that there's no error */
3570c16b537SWarner Losh     if (state.state->mode != GZ_READ ||
3580c16b537SWarner Losh             (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))
3590c16b537SWarner Losh         return -1;
3600c16b537SWarner Losh 
3610c16b537SWarner Losh     /* back up and start over */
3620c16b537SWarner Losh     if (LSEEK(state.state->fd, state.state->start, SEEK_SET) == -1)
3630c16b537SWarner Losh         return -1;
3640c16b537SWarner Losh     gz_reset(state);
3650c16b537SWarner Losh     return 0;
3660c16b537SWarner Losh }
3670c16b537SWarner Losh 
3680c16b537SWarner Losh /* -- see zlib.h -- */
gzseek64(file,offset,whence)3690c16b537SWarner Losh z_off64_t ZEXPORT gzseek64(file, offset, whence)
3700c16b537SWarner Losh     gzFile file;
3710c16b537SWarner Losh     z_off64_t offset;
3720c16b537SWarner Losh     int whence;
3730c16b537SWarner Losh {
3740c16b537SWarner Losh     unsigned n;
3750c16b537SWarner Losh     z_off64_t ret;
3760c16b537SWarner Losh     gz_statep state;
3770c16b537SWarner Losh 
3780c16b537SWarner Losh     /* get internal structure and check integrity */
3790c16b537SWarner Losh     if (file == NULL)
3800c16b537SWarner Losh         return -1;
381*9cbefe25SConrad Meyer     state.file = file;
3820c16b537SWarner Losh     if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)
3830c16b537SWarner Losh         return -1;
3840c16b537SWarner Losh 
3850c16b537SWarner Losh     /* check that there's no error */
3860c16b537SWarner Losh     if (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR)
3870c16b537SWarner Losh         return -1;
3880c16b537SWarner Losh 
3890c16b537SWarner Losh     /* can only seek from start or relative to current position */
3900c16b537SWarner Losh     if (whence != SEEK_SET && whence != SEEK_CUR)
3910c16b537SWarner Losh         return -1;
3920c16b537SWarner Losh 
3930c16b537SWarner Losh     /* normalize offset to a SEEK_CUR specification */
3940c16b537SWarner Losh     if (whence == SEEK_SET)
3950c16b537SWarner Losh         offset -= state.state->x.pos;
3960c16b537SWarner Losh     else if (state.state->seek)
3970c16b537SWarner Losh         offset += state.state->skip;
3980c16b537SWarner Losh     state.state->seek = 0;
3990c16b537SWarner Losh 
4000c16b537SWarner Losh     /* if within raw area while reading, just go there */
4010c16b537SWarner Losh     if (state.state->mode == GZ_READ && state.state->how == COPY &&
4020c16b537SWarner Losh             state.state->x.pos + offset >= 0) {
4030c16b537SWarner Losh         ret = LSEEK(state.state->fd, offset - state.state->x.have, SEEK_CUR);
4040c16b537SWarner Losh         if (ret == -1)
4050c16b537SWarner Losh             return -1;
4060c16b537SWarner Losh         state.state->x.have = 0;
4070c16b537SWarner Losh         state.state->eof = 0;
4080c16b537SWarner Losh         state.state->past = 0;
4090c16b537SWarner Losh         state.state->seek = 0;
4100c16b537SWarner Losh         gz_error(state, Z_OK, NULL);
4110c16b537SWarner Losh         state.state->strm.avail_in = 0;
4120c16b537SWarner Losh         state.state->x.pos += offset;
4130c16b537SWarner Losh         return state.state->x.pos;
4140c16b537SWarner Losh     }
4150c16b537SWarner Losh 
4160c16b537SWarner Losh     /* calculate skip amount, rewinding if needed for back seek when reading */
4170c16b537SWarner Losh     if (offset < 0) {
4180c16b537SWarner Losh         if (state.state->mode != GZ_READ)         /* writing -- can't go backwards */
4190c16b537SWarner Losh             return -1;
4200c16b537SWarner Losh         offset += state.state->x.pos;
4210c16b537SWarner Losh         if (offset < 0)                     /* before start of file! */
4220c16b537SWarner Losh             return -1;
4230c16b537SWarner Losh         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
4240c16b537SWarner Losh             return -1;
4250c16b537SWarner Losh     }
4260c16b537SWarner Losh 
4270c16b537SWarner Losh     /* if reading, skip what's in output buffer (one less gzgetc() check) */
4280c16b537SWarner Losh     if (state.state->mode == GZ_READ) {
4290c16b537SWarner Losh         n = GT_OFF(state.state->x.have) || (z_off64_t)state.state->x.have > offset ?
4300c16b537SWarner Losh             (unsigned)offset : state.state->x.have;
4310c16b537SWarner Losh         state.state->x.have -= n;
4320c16b537SWarner Losh         state.state->x.next += n;
4330c16b537SWarner Losh         state.state->x.pos += n;
4340c16b537SWarner Losh         offset -= n;
4350c16b537SWarner Losh     }
4360c16b537SWarner Losh 
4370c16b537SWarner Losh     /* request skip (if not zero) */
4380c16b537SWarner Losh     if (offset) {
4390c16b537SWarner Losh         state.state->seek = 1;
4400c16b537SWarner Losh         state.state->skip = offset;
4410c16b537SWarner Losh     }
4420c16b537SWarner Losh     return state.state->x.pos + offset;
4430c16b537SWarner Losh }
4440c16b537SWarner Losh 
4450c16b537SWarner Losh /* -- see zlib.h -- */
gzseek(file,offset,whence)4460c16b537SWarner Losh z_off_t ZEXPORT gzseek(file, offset, whence)
4470c16b537SWarner Losh     gzFile file;
4480c16b537SWarner Losh     z_off_t offset;
4490c16b537SWarner Losh     int whence;
4500c16b537SWarner Losh {
4510c16b537SWarner Losh     z_off64_t ret;
4520c16b537SWarner Losh 
4530c16b537SWarner Losh     ret = gzseek64(file, (z_off64_t)offset, whence);
4540c16b537SWarner Losh     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
4550c16b537SWarner Losh }
4560c16b537SWarner Losh 
4570c16b537SWarner Losh /* -- see zlib.h -- */
gztell64(file)4580c16b537SWarner Losh z_off64_t ZEXPORT gztell64(file)
4590c16b537SWarner Losh     gzFile file;
4600c16b537SWarner Losh {
4610c16b537SWarner Losh     gz_statep state;
4620c16b537SWarner Losh 
4630c16b537SWarner Losh     /* get internal structure and check integrity */
4640c16b537SWarner Losh     if (file == NULL)
4650c16b537SWarner Losh         return -1;
466*9cbefe25SConrad Meyer     state.file = file;
4670c16b537SWarner Losh     if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)
4680c16b537SWarner Losh         return -1;
4690c16b537SWarner Losh 
4700c16b537SWarner Losh     /* return position */
4710c16b537SWarner Losh     return state.state->x.pos + (state.state->seek ? state.state->skip : 0);
4720c16b537SWarner Losh }
4730c16b537SWarner Losh 
4740c16b537SWarner Losh /* -- see zlib.h -- */
gztell(file)4750c16b537SWarner Losh z_off_t ZEXPORT gztell(file)
4760c16b537SWarner Losh     gzFile file;
4770c16b537SWarner Losh {
4780c16b537SWarner Losh     z_off64_t ret;
4790c16b537SWarner Losh 
4800c16b537SWarner Losh     ret = gztell64(file);
4810c16b537SWarner Losh     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
4820c16b537SWarner Losh }
4830c16b537SWarner Losh 
4840c16b537SWarner Losh /* -- see zlib.h -- */
gzoffset64(file)4850c16b537SWarner Losh z_off64_t ZEXPORT gzoffset64(file)
4860c16b537SWarner Losh     gzFile file;
4870c16b537SWarner Losh {
4880c16b537SWarner Losh     z_off64_t offset;
4890c16b537SWarner Losh     gz_statep state;
4900c16b537SWarner Losh 
4910c16b537SWarner Losh     /* get internal structure and check integrity */
4920c16b537SWarner Losh     if (file == NULL)
4930c16b537SWarner Losh         return -1;
494*9cbefe25SConrad Meyer     state.file = file;
4950c16b537SWarner Losh     if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)
4960c16b537SWarner Losh         return -1;
4970c16b537SWarner Losh 
4980c16b537SWarner Losh     /* compute and return effective offset in file */
4990c16b537SWarner Losh     offset = LSEEK(state.state->fd, 0, SEEK_CUR);
5000c16b537SWarner Losh     if (offset == -1)
5010c16b537SWarner Losh         return -1;
5020c16b537SWarner Losh     if (state.state->mode == GZ_READ)             /* reading */
5030c16b537SWarner Losh         offset -= state.state->strm.avail_in;     /* don't count buffered input */
5040c16b537SWarner Losh     return offset;
5050c16b537SWarner Losh }
5060c16b537SWarner Losh 
5070c16b537SWarner Losh /* -- see zlib.h -- */
gzoffset(file)5080c16b537SWarner Losh z_off_t ZEXPORT gzoffset(file)
5090c16b537SWarner Losh     gzFile file;
5100c16b537SWarner Losh {
5110c16b537SWarner Losh     z_off64_t ret;
5120c16b537SWarner Losh 
5130c16b537SWarner Losh     ret = gzoffset64(file);
5140c16b537SWarner Losh     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
5150c16b537SWarner Losh }
5160c16b537SWarner Losh 
5170c16b537SWarner Losh /* -- see zlib.h -- */
gzeof(file)5180c16b537SWarner Losh int ZEXPORT gzeof(file)
5190c16b537SWarner Losh     gzFile file;
5200c16b537SWarner Losh {
5210c16b537SWarner Losh     gz_statep state;
5220c16b537SWarner Losh 
5230c16b537SWarner Losh     /* get internal structure and check integrity */
5240c16b537SWarner Losh     if (file == NULL)
5250c16b537SWarner Losh         return 0;
526*9cbefe25SConrad Meyer     state.file = file;
5270c16b537SWarner Losh     if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)
5280c16b537SWarner Losh         return 0;
5290c16b537SWarner Losh 
5300c16b537SWarner Losh     /* return end-of-file state */
5310c16b537SWarner Losh     return state.state->mode == GZ_READ ? state.state->past : 0;
5320c16b537SWarner Losh }
5330c16b537SWarner Losh 
5340c16b537SWarner Losh /* -- see zlib.h -- */
gzerror(file,errnum)5350c16b537SWarner Losh const char * ZEXPORT gzerror(file, errnum)
5360c16b537SWarner Losh     gzFile file;
5370c16b537SWarner Losh     int *errnum;
5380c16b537SWarner Losh {
5390c16b537SWarner Losh     gz_statep state;
5400c16b537SWarner Losh 
5410c16b537SWarner Losh     /* get internal structure and check integrity */
5420c16b537SWarner Losh     if (file == NULL)
5430c16b537SWarner Losh         return NULL;
544*9cbefe25SConrad Meyer     state.file = file;
5450c16b537SWarner Losh     if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)
5460c16b537SWarner Losh         return NULL;
5470c16b537SWarner Losh 
5480c16b537SWarner Losh     /* return error information */
5490c16b537SWarner Losh     if (errnum != NULL)
5500c16b537SWarner Losh         *errnum = state.state->err;
5510c16b537SWarner Losh     return state.state->err == Z_MEM_ERROR ? "out of memory" :
5520c16b537SWarner Losh                                        (state.state->msg == NULL ? "" : state.state->msg);
5530c16b537SWarner Losh }
5540c16b537SWarner Losh 
5550c16b537SWarner Losh /* -- see zlib.h -- */
gzclearerr(file)5560c16b537SWarner Losh void ZEXPORT gzclearerr(file)
5570c16b537SWarner Losh     gzFile file;
5580c16b537SWarner Losh {
5590c16b537SWarner Losh     gz_statep state;
5600c16b537SWarner Losh 
5610c16b537SWarner Losh     /* get internal structure and check integrity */
5620c16b537SWarner Losh     if (file == NULL)
5630c16b537SWarner Losh         return;
564*9cbefe25SConrad Meyer     state.file = file;
5650c16b537SWarner Losh     if (state.state->mode != GZ_READ && state.state->mode != GZ_WRITE)
5660c16b537SWarner Losh         return;
5670c16b537SWarner Losh 
5680c16b537SWarner Losh     /* clear error and end-of-file */
5690c16b537SWarner Losh     if (state.state->mode == GZ_READ) {
5700c16b537SWarner Losh         state.state->eof = 0;
5710c16b537SWarner Losh         state.state->past = 0;
5720c16b537SWarner Losh     }
5730c16b537SWarner Losh     gz_error(state, Z_OK, NULL);
5740c16b537SWarner Losh }
5750c16b537SWarner Losh 
5760c16b537SWarner Losh /* Create an error message in allocated memory and set state.state->err and
5770c16b537SWarner Losh    state.state->msg accordingly.  Free any previous error message already there.  Do
5780c16b537SWarner Losh    not try to free or allocate space if the error is Z_MEM_ERROR (out of
5790c16b537SWarner Losh    memory).  Simply save the error message as a static string.  If there is an
5800c16b537SWarner Losh    allocation failure constructing the error message, then convert the error to
5810c16b537SWarner Losh    out of memory. */
gz_error(state,err,msg)5820c16b537SWarner Losh void ZLIB_INTERNAL gz_error(state, err, msg)
5830c16b537SWarner Losh     gz_statep state;
5840c16b537SWarner Losh     int err;
5850c16b537SWarner Losh     const char *msg;
5860c16b537SWarner Losh {
5870c16b537SWarner Losh     /* free previously allocated message and clear */
5880c16b537SWarner Losh     if (state.state->msg != NULL) {
5890c16b537SWarner Losh         if (state.state->err != Z_MEM_ERROR)
5900c16b537SWarner Losh             free(state.state->msg);
5910c16b537SWarner Losh         state.state->msg = NULL;
5920c16b537SWarner Losh     }
5930c16b537SWarner Losh 
5940c16b537SWarner Losh     /* if fatal, set state.state->x.have to 0 so that the gzgetc() macro fails */
5950c16b537SWarner Losh     if (err != Z_OK && err != Z_BUF_ERROR)
5960c16b537SWarner Losh         state.state->x.have = 0;
5970c16b537SWarner Losh 
5980c16b537SWarner Losh     /* set error code, and if no message, then done */
5990c16b537SWarner Losh     state.state->err = err;
6000c16b537SWarner Losh     if (msg == NULL)
6010c16b537SWarner Losh         return;
6020c16b537SWarner Losh 
6030c16b537SWarner Losh     /* for an out of memory error, return literal string when requested */
6040c16b537SWarner Losh     if (err == Z_MEM_ERROR)
6050c16b537SWarner Losh         return;
6060c16b537SWarner Losh 
6070c16b537SWarner Losh     /* construct error message with path */
6080c16b537SWarner Losh     if ((state.state->msg = (char *)malloc(strlen(state.state->path) + strlen(msg) + 3)) ==
6090c16b537SWarner Losh             NULL) {
6100c16b537SWarner Losh         state.state->err = Z_MEM_ERROR;
6110c16b537SWarner Losh         return;
6120c16b537SWarner Losh     }
6130c16b537SWarner Losh #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
6140c16b537SWarner Losh     (void)snprintf(state.state->msg, strlen(state.state->path) + strlen(msg) + 3,
6150c16b537SWarner Losh                    "%s%s%s", state.state->path, ": ", msg);
6160c16b537SWarner Losh #else
6170c16b537SWarner Losh     strcpy(state.state->msg, state.state->path);
6180c16b537SWarner Losh     strcat(state.state->msg, ": ");
6190c16b537SWarner Losh     strcat(state.state->msg, msg);
6200c16b537SWarner Losh #endif
6210c16b537SWarner Losh }
6220c16b537SWarner Losh 
6230c16b537SWarner Losh #ifndef INT_MAX
6240c16b537SWarner Losh /* portably return maximum value for an int (when limits.h presumed not
6250c16b537SWarner Losh    available) -- we need to do this to cover cases where 2's complement not
6260c16b537SWarner Losh    used, since C standard permits 1's complement and sign-bit representations,
6270c16b537SWarner Losh    otherwise we could just use ((unsigned)-1) >> 1 */
gz_intmax()6280c16b537SWarner Losh unsigned ZLIB_INTERNAL gz_intmax()
6290c16b537SWarner Losh {
6300c16b537SWarner Losh     unsigned p, q;
6310c16b537SWarner Losh 
6320c16b537SWarner Losh     p = 1;
6330c16b537SWarner Losh     do {
6340c16b537SWarner Losh         q = p;
6350c16b537SWarner Losh         p <<= 1;
6360c16b537SWarner Losh         p++;
6370c16b537SWarner Losh     } while (p > q);
6380c16b537SWarner Losh     return q >> 1;
6390c16b537SWarner Losh }
6400c16b537SWarner Losh #endif
641