Home | History | Annotate | Line # | Download | only in zlib
      1      1.1  christos /* gzlib.c -- zlib functions common to reading and writing gzip files
      2  1.1.1.3  christos  * Copyright (C) 2004-2024 Mark Adler
      3      1.1  christos  * For conditions of distribution and use, see copyright notice in zlib.h
      4      1.1  christos  */
      5      1.1  christos 
      6      1.1  christos #include "gzguts.h"
      7      1.1  christos 
      8  1.1.1.2  christos #if defined(_WIN32) && !defined(__BORLANDC__)
      9      1.1  christos #  define LSEEK _lseeki64
     10      1.1  christos #else
     11      1.1  christos #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
     12      1.1  christos #  define LSEEK lseek64
     13      1.1  christos #else
     14      1.1  christos #  define LSEEK lseek
     15      1.1  christos #endif
     16      1.1  christos #endif
     17      1.1  christos 
     18      1.1  christos #if defined UNDER_CE
     19      1.1  christos 
     20      1.1  christos /* Map the Windows error number in ERROR to a locale-dependent error message
     21      1.1  christos    string and return a pointer to it.  Typically, the values for ERROR come
     22      1.1  christos    from GetLastError.
     23      1.1  christos 
     24      1.1  christos    The string pointed to shall not be modified by the application, but may be
     25      1.1  christos    overwritten by a subsequent call to gz_strwinerror
     26      1.1  christos 
     27      1.1  christos    The gz_strwinerror function does not change the current setting of
     28      1.1  christos    GetLastError. */
     29  1.1.1.3  christos char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
     30      1.1  christos     static char buf[1024];
     31      1.1  christos 
     32      1.1  christos     wchar_t *msgbuf;
     33      1.1  christos     DWORD lasterr = GetLastError();
     34      1.1  christos     DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
     35      1.1  christos         | FORMAT_MESSAGE_ALLOCATE_BUFFER,
     36      1.1  christos         NULL,
     37      1.1  christos         error,
     38      1.1  christos         0, /* Default language */
     39      1.1  christos         (LPVOID)&msgbuf,
     40      1.1  christos         0,
     41      1.1  christos         NULL);
     42      1.1  christos     if (chars != 0) {
     43      1.1  christos         /* If there is an \r\n appended, zap it.  */
     44      1.1  christos         if (chars >= 2
     45      1.1  christos             && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
     46      1.1  christos             chars -= 2;
     47      1.1  christos             msgbuf[chars] = 0;
     48      1.1  christos         }
     49      1.1  christos 
     50      1.1  christos         if (chars > sizeof (buf) - 1) {
     51      1.1  christos             chars = sizeof (buf) - 1;
     52      1.1  christos             msgbuf[chars] = 0;
     53      1.1  christos         }
     54      1.1  christos 
     55      1.1  christos         wcstombs(buf, msgbuf, chars + 1);
     56      1.1  christos         LocalFree(msgbuf);
     57      1.1  christos     }
     58      1.1  christos     else {
     59      1.1  christos         sprintf(buf, "unknown win32 error (%ld)", error);
     60      1.1  christos     }
     61      1.1  christos 
     62      1.1  christos     SetLastError(lasterr);
     63      1.1  christos     return buf;
     64      1.1  christos }
     65      1.1  christos 
     66      1.1  christos #endif /* UNDER_CE */
     67      1.1  christos 
     68      1.1  christos /* Reset gzip file state */
     69  1.1.1.3  christos local void gz_reset(gz_statep state) {
     70      1.1  christos     state->x.have = 0;              /* no output data available */
     71      1.1  christos     if (state->mode == GZ_READ) {   /* for reading ... */
     72      1.1  christos         state->eof = 0;             /* not at end of file */
     73      1.1  christos         state->past = 0;            /* have not read past end yet */
     74      1.1  christos         state->how = LOOK;          /* look for gzip header */
     75      1.1  christos     }
     76  1.1.1.2  christos     else                            /* for writing ... */
     77  1.1.1.2  christos         state->reset = 0;           /* no deflateReset pending */
     78      1.1  christos     state->seek = 0;                /* no seek request pending */
     79      1.1  christos     gz_error(state, Z_OK, NULL);    /* clear error */
     80      1.1  christos     state->x.pos = 0;               /* no uncompressed data yet */
     81      1.1  christos     state->strm.avail_in = 0;       /* no input data yet */
     82      1.1  christos }
     83      1.1  christos 
     84      1.1  christos /* Open a gzip file either by name or file descriptor. */
     85  1.1.1.3  christos local gzFile gz_open(const void *path, int fd, const char *mode) {
     86      1.1  christos     gz_statep state;
     87      1.1  christos     z_size_t len;
     88      1.1  christos     int oflag;
     89      1.1  christos #ifdef O_CLOEXEC
     90      1.1  christos     int cloexec = 0;
     91      1.1  christos #endif
     92      1.1  christos #ifdef O_EXCL
     93      1.1  christos     int exclusive = 0;
     94      1.1  christos #endif
     95      1.1  christos 
     96      1.1  christos     /* check input */
     97      1.1  christos     if (path == NULL)
     98      1.1  christos         return NULL;
     99      1.1  christos 
    100      1.1  christos     /* allocate gzFile structure to return */
    101      1.1  christos     state = (gz_statep)malloc(sizeof(gz_state));
    102      1.1  christos     if (state == NULL)
    103      1.1  christos         return NULL;
    104      1.1  christos     state->size = 0;            /* no buffers allocated yet */
    105      1.1  christos     state->want = GZBUFSIZE;    /* requested buffer size */
    106      1.1  christos     state->msg = NULL;          /* no error message yet */
    107      1.1  christos 
    108      1.1  christos     /* interpret mode */
    109      1.1  christos     state->mode = GZ_NONE;
    110      1.1  christos     state->level = Z_DEFAULT_COMPRESSION;
    111      1.1  christos     state->strategy = Z_DEFAULT_STRATEGY;
    112      1.1  christos     state->direct = 0;
    113      1.1  christos     while (*mode) {
    114      1.1  christos         if (*mode >= '0' && *mode <= '9')
    115      1.1  christos             state->level = *mode - '0';
    116      1.1  christos         else
    117      1.1  christos             switch (*mode) {
    118      1.1  christos             case 'r':
    119      1.1  christos                 state->mode = GZ_READ;
    120      1.1  christos                 break;
    121      1.1  christos #ifndef NO_GZCOMPRESS
    122      1.1  christos             case 'w':
    123      1.1  christos                 state->mode = GZ_WRITE;
    124      1.1  christos                 break;
    125      1.1  christos             case 'a':
    126      1.1  christos                 state->mode = GZ_APPEND;
    127      1.1  christos                 break;
    128      1.1  christos #endif
    129      1.1  christos             case '+':       /* can't read and write at the same time */
    130      1.1  christos                 free(state);
    131      1.1  christos                 return NULL;
    132      1.1  christos             case 'b':       /* ignore -- will request binary anyway */
    133      1.1  christos                 break;
    134      1.1  christos #ifdef O_CLOEXEC
    135      1.1  christos             case 'e':
    136      1.1  christos                 cloexec = 1;
    137      1.1  christos                 break;
    138      1.1  christos #endif
    139      1.1  christos #ifdef O_EXCL
    140      1.1  christos             case 'x':
    141      1.1  christos                 exclusive = 1;
    142      1.1  christos                 break;
    143      1.1  christos #endif
    144      1.1  christos             case 'f':
    145      1.1  christos                 state->strategy = Z_FILTERED;
    146      1.1  christos                 break;
    147      1.1  christos             case 'h':
    148      1.1  christos                 state->strategy = Z_HUFFMAN_ONLY;
    149      1.1  christos                 break;
    150      1.1  christos             case 'R':
    151      1.1  christos                 state->strategy = Z_RLE;
    152      1.1  christos                 break;
    153      1.1  christos             case 'F':
    154      1.1  christos                 state->strategy = Z_FIXED;
    155      1.1  christos                 break;
    156      1.1  christos             case 'T':
    157      1.1  christos                 state->direct = 1;
    158      1.1  christos                 break;
    159      1.1  christos             default:        /* could consider as an error, but just ignore */
    160      1.1  christos                 ;
    161      1.1  christos             }
    162      1.1  christos         mode++;
    163      1.1  christos     }
    164      1.1  christos 
    165      1.1  christos     /* must provide an "r", "w", or "a" */
    166      1.1  christos     if (state->mode == GZ_NONE) {
    167      1.1  christos         free(state);
    168      1.1  christos         return NULL;
    169      1.1  christos     }
    170      1.1  christos 
    171      1.1  christos     /* can't force transparent read */
    172      1.1  christos     if (state->mode == GZ_READ) {
    173      1.1  christos         if (state->direct) {
    174      1.1  christos             free(state);
    175      1.1  christos             return NULL;
    176      1.1  christos         }
    177      1.1  christos         state->direct = 1;      /* for empty file */
    178      1.1  christos     }
    179      1.1  christos 
    180      1.1  christos     /* save the path name for error messages */
    181      1.1  christos #ifdef WIDECHAR
    182      1.1  christos     if (fd == -2) {
    183      1.1  christos         len = wcstombs(NULL, path, 0);
    184      1.1  christos         if (len == (z_size_t)-1)
    185      1.1  christos             len = 0;
    186      1.1  christos     }
    187      1.1  christos     else
    188      1.1  christos #endif
    189      1.1  christos         len = strlen((const char *)path);
    190      1.1  christos     state->path = (char *)malloc(len + 1);
    191      1.1  christos     if (state->path == NULL) {
    192      1.1  christos         free(state);
    193      1.1  christos         return NULL;
    194      1.1  christos     }
    195      1.1  christos #ifdef WIDECHAR
    196      1.1  christos     if (fd == -2)
    197      1.1  christos         if (len)
    198      1.1  christos             wcstombs(state->path, path, len + 1);
    199      1.1  christos         else
    200      1.1  christos             *(state->path) = 0;
    201      1.1  christos     else
    202      1.1  christos #endif
    203      1.1  christos #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
    204      1.1  christos         (void)snprintf(state->path, len + 1, "%s", (const char *)path);
    205      1.1  christos #else
    206      1.1  christos         strcpy(state->path, path);
    207      1.1  christos #endif
    208      1.1  christos 
    209      1.1  christos     /* compute the flags for open() */
    210      1.1  christos     oflag =
    211      1.1  christos #ifdef O_LARGEFILE
    212      1.1  christos         O_LARGEFILE |
    213      1.1  christos #endif
    214      1.1  christos #ifdef O_BINARY
    215      1.1  christos         O_BINARY |
    216      1.1  christos #endif
    217      1.1  christos #ifdef O_CLOEXEC
    218      1.1  christos         (cloexec ? O_CLOEXEC : 0) |
    219      1.1  christos #endif
    220      1.1  christos         (state->mode == GZ_READ ?
    221      1.1  christos          O_RDONLY :
    222      1.1  christos          (O_WRONLY | O_CREAT |
    223      1.1  christos #ifdef O_EXCL
    224      1.1  christos           (exclusive ? O_EXCL : 0) |
    225      1.1  christos #endif
    226      1.1  christos           (state->mode == GZ_WRITE ?
    227      1.1  christos            O_TRUNC :
    228      1.1  christos            O_APPEND)));
    229      1.1  christos 
    230      1.1  christos     /* open the file with the appropriate flags (or just use fd) */
    231      1.1  christos     state->fd = fd > -1 ? fd : (
    232      1.1  christos #ifdef WIDECHAR
    233      1.1  christos         fd == -2 ? _wopen(path, oflag, 0666) :
    234      1.1  christos #endif
    235      1.1  christos         open((const char *)path, oflag, 0666));
    236      1.1  christos     if (state->fd == -1) {
    237      1.1  christos         free(state->path);
    238      1.1  christos         free(state);
    239      1.1  christos         return NULL;
    240      1.1  christos     }
    241      1.1  christos     if (state->mode == GZ_APPEND) {
    242      1.1  christos         LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
    243      1.1  christos         state->mode = GZ_WRITE;         /* simplify later checks */
    244      1.1  christos     }
    245      1.1  christos 
    246      1.1  christos     /* save the current position for rewinding (only if reading) */
    247      1.1  christos     if (state->mode == GZ_READ) {
    248      1.1  christos         state->start = LSEEK(state->fd, 0, SEEK_CUR);
    249      1.1  christos         if (state->start == -1) state->start = 0;
    250      1.1  christos     }
    251      1.1  christos 
    252      1.1  christos     /* initialize stream */
    253      1.1  christos     gz_reset(state);
    254      1.1  christos 
    255      1.1  christos     /* return stream */
    256      1.1  christos     return (gzFile)state;
    257      1.1  christos }
    258      1.1  christos 
    259      1.1  christos /* -- see zlib.h -- */
    260  1.1.1.3  christos gzFile ZEXPORT gzopen(const char *path, const char *mode) {
    261      1.1  christos     return gz_open(path, -1, mode);
    262      1.1  christos }
    263      1.1  christos 
    264      1.1  christos /* -- see zlib.h -- */
    265  1.1.1.3  christos gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
    266      1.1  christos     return gz_open(path, -1, mode);
    267      1.1  christos }
    268      1.1  christos 
    269      1.1  christos /* -- see zlib.h -- */
    270  1.1.1.3  christos gzFile ZEXPORT gzdopen(int fd, const char *mode) {
    271      1.1  christos     char *path;         /* identifier for error messages */
    272      1.1  christos     gzFile gz;
    273      1.1  christos 
    274      1.1  christos     if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
    275      1.1  christos         return NULL;
    276      1.1  christos #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
    277      1.1  christos     (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
    278      1.1  christos #else
    279      1.1  christos     sprintf(path, "<fd:%d>", fd);   /* for debugging */
    280      1.1  christos #endif
    281      1.1  christos     gz = gz_open(path, fd, mode);
    282      1.1  christos     free(path);
    283      1.1  christos     return gz;
    284      1.1  christos }
    285      1.1  christos 
    286      1.1  christos /* -- see zlib.h -- */
    287      1.1  christos #ifdef WIDECHAR
    288  1.1.1.3  christos gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
    289      1.1  christos     return gz_open(path, -2, mode);
    290      1.1  christos }
    291      1.1  christos #endif
    292      1.1  christos 
    293      1.1  christos /* -- see zlib.h -- */
    294  1.1.1.3  christos int ZEXPORT gzbuffer(gzFile file, unsigned size) {
    295      1.1  christos     gz_statep state;
    296      1.1  christos 
    297      1.1  christos     /* get internal structure and check integrity */
    298      1.1  christos     if (file == NULL)
    299      1.1  christos         return -1;
    300      1.1  christos     state = (gz_statep)file;
    301      1.1  christos     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    302      1.1  christos         return -1;
    303      1.1  christos 
    304      1.1  christos     /* make sure we haven't already allocated memory */
    305      1.1  christos     if (state->size != 0)
    306      1.1  christos         return -1;
    307      1.1  christos 
    308      1.1  christos     /* check and set requested size */
    309      1.1  christos     if ((size << 1) < size)
    310      1.1  christos         return -1;              /* need to be able to double it */
    311  1.1.1.3  christos     if (size < 8)
    312  1.1.1.3  christos         size = 8;               /* needed to behave well with flushing */
    313      1.1  christos     state->want = size;
    314      1.1  christos     return 0;
    315      1.1  christos }
    316      1.1  christos 
    317      1.1  christos /* -- see zlib.h -- */
    318  1.1.1.3  christos int ZEXPORT gzrewind(gzFile file) {
    319      1.1  christos     gz_statep state;
    320      1.1  christos 
    321      1.1  christos     /* get internal structure */
    322      1.1  christos     if (file == NULL)
    323      1.1  christos         return -1;
    324      1.1  christos     state = (gz_statep)file;
    325      1.1  christos 
    326      1.1  christos     /* check that we're reading and that there's no error */
    327      1.1  christos     if (state->mode != GZ_READ ||
    328      1.1  christos             (state->err != Z_OK && state->err != Z_BUF_ERROR))
    329      1.1  christos         return -1;
    330      1.1  christos 
    331      1.1  christos     /* back up and start over */
    332      1.1  christos     if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
    333      1.1  christos         return -1;
    334      1.1  christos     gz_reset(state);
    335      1.1  christos     return 0;
    336      1.1  christos }
    337      1.1  christos 
    338      1.1  christos /* -- see zlib.h -- */
    339  1.1.1.3  christos z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
    340      1.1  christos     unsigned n;
    341      1.1  christos     z_off64_t ret;
    342      1.1  christos     gz_statep state;
    343      1.1  christos 
    344      1.1  christos     /* get internal structure and check integrity */
    345      1.1  christos     if (file == NULL)
    346      1.1  christos         return -1;
    347      1.1  christos     state = (gz_statep)file;
    348      1.1  christos     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    349      1.1  christos         return -1;
    350      1.1  christos 
    351      1.1  christos     /* check that there's no error */
    352      1.1  christos     if (state->err != Z_OK && state->err != Z_BUF_ERROR)
    353      1.1  christos         return -1;
    354      1.1  christos 
    355      1.1  christos     /* can only seek from start or relative to current position */
    356      1.1  christos     if (whence != SEEK_SET && whence != SEEK_CUR)
    357      1.1  christos         return -1;
    358      1.1  christos 
    359      1.1  christos     /* normalize offset to a SEEK_CUR specification */
    360      1.1  christos     if (whence == SEEK_SET)
    361      1.1  christos         offset -= state->x.pos;
    362      1.1  christos     else if (state->seek)
    363      1.1  christos         offset += state->skip;
    364      1.1  christos     state->seek = 0;
    365      1.1  christos 
    366      1.1  christos     /* if within raw area while reading, just go there */
    367      1.1  christos     if (state->mode == GZ_READ && state->how == COPY &&
    368      1.1  christos             state->x.pos + offset >= 0) {
    369  1.1.1.2  christos         ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
    370      1.1  christos         if (ret == -1)
    371      1.1  christos             return -1;
    372      1.1  christos         state->x.have = 0;
    373      1.1  christos         state->eof = 0;
    374      1.1  christos         state->past = 0;
    375      1.1  christos         state->seek = 0;
    376      1.1  christos         gz_error(state, Z_OK, NULL);
    377      1.1  christos         state->strm.avail_in = 0;
    378      1.1  christos         state->x.pos += offset;
    379      1.1  christos         return state->x.pos;
    380      1.1  christos     }
    381      1.1  christos 
    382      1.1  christos     /* calculate skip amount, rewinding if needed for back seek when reading */
    383      1.1  christos     if (offset < 0) {
    384      1.1  christos         if (state->mode != GZ_READ)         /* writing -- can't go backwards */
    385      1.1  christos             return -1;
    386      1.1  christos         offset += state->x.pos;
    387      1.1  christos         if (offset < 0)                     /* before start of file! */
    388      1.1  christos             return -1;
    389      1.1  christos         if (gzrewind(file) == -1)           /* rewind, then skip to offset */
    390      1.1  christos             return -1;
    391      1.1  christos     }
    392      1.1  christos 
    393      1.1  christos     /* if reading, skip what's in output buffer (one less gzgetc() check) */
    394      1.1  christos     if (state->mode == GZ_READ) {
    395      1.1  christos         n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
    396      1.1  christos             (unsigned)offset : state->x.have;
    397      1.1  christos         state->x.have -= n;
    398      1.1  christos         state->x.next += n;
    399      1.1  christos         state->x.pos += n;
    400      1.1  christos         offset -= n;
    401      1.1  christos     }
    402      1.1  christos 
    403      1.1  christos     /* request skip (if not zero) */
    404      1.1  christos     if (offset) {
    405      1.1  christos         state->seek = 1;
    406      1.1  christos         state->skip = offset;
    407      1.1  christos     }
    408      1.1  christos     return state->x.pos + offset;
    409      1.1  christos }
    410      1.1  christos 
    411      1.1  christos /* -- see zlib.h -- */
    412  1.1.1.3  christos z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
    413      1.1  christos     z_off64_t ret;
    414      1.1  christos 
    415      1.1  christos     ret = gzseek64(file, (z_off64_t)offset, whence);
    416      1.1  christos     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
    417      1.1  christos }
    418      1.1  christos 
    419      1.1  christos /* -- see zlib.h -- */
    420  1.1.1.3  christos z_off64_t ZEXPORT gztell64(gzFile file) {
    421      1.1  christos     gz_statep state;
    422      1.1  christos 
    423      1.1  christos     /* get internal structure and check integrity */
    424      1.1  christos     if (file == NULL)
    425      1.1  christos         return -1;
    426      1.1  christos     state = (gz_statep)file;
    427      1.1  christos     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    428      1.1  christos         return -1;
    429      1.1  christos 
    430      1.1  christos     /* return position */
    431      1.1  christos     return state->x.pos + (state->seek ? state->skip : 0);
    432      1.1  christos }
    433      1.1  christos 
    434      1.1  christos /* -- see zlib.h -- */
    435  1.1.1.3  christos z_off_t ZEXPORT gztell(gzFile file) {
    436      1.1  christos     z_off64_t ret;
    437      1.1  christos 
    438      1.1  christos     ret = gztell64(file);
    439      1.1  christos     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
    440      1.1  christos }
    441      1.1  christos 
    442      1.1  christos /* -- see zlib.h -- */
    443  1.1.1.3  christos z_off64_t ZEXPORT gzoffset64(gzFile file) {
    444      1.1  christos     z_off64_t offset;
    445      1.1  christos     gz_statep state;
    446      1.1  christos 
    447      1.1  christos     /* get internal structure and check integrity */
    448      1.1  christos     if (file == NULL)
    449      1.1  christos         return -1;
    450      1.1  christos     state = (gz_statep)file;
    451      1.1  christos     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    452      1.1  christos         return -1;
    453      1.1  christos 
    454      1.1  christos     /* compute and return effective offset in file */
    455      1.1  christos     offset = LSEEK(state->fd, 0, SEEK_CUR);
    456      1.1  christos     if (offset == -1)
    457      1.1  christos         return -1;
    458      1.1  christos     if (state->mode == GZ_READ)             /* reading */
    459      1.1  christos         offset -= state->strm.avail_in;     /* don't count buffered input */
    460      1.1  christos     return offset;
    461      1.1  christos }
    462      1.1  christos 
    463      1.1  christos /* -- see zlib.h -- */
    464  1.1.1.3  christos z_off_t ZEXPORT gzoffset(gzFile file) {
    465      1.1  christos     z_off64_t ret;
    466      1.1  christos 
    467      1.1  christos     ret = gzoffset64(file);
    468      1.1  christos     return ret == (z_off_t)ret ? (z_off_t)ret : -1;
    469      1.1  christos }
    470      1.1  christos 
    471      1.1  christos /* -- see zlib.h -- */
    472  1.1.1.3  christos int ZEXPORT gzeof(gzFile file) {
    473      1.1  christos     gz_statep state;
    474      1.1  christos 
    475      1.1  christos     /* get internal structure and check integrity */
    476      1.1  christos     if (file == NULL)
    477      1.1  christos         return 0;
    478      1.1  christos     state = (gz_statep)file;
    479      1.1  christos     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    480      1.1  christos         return 0;
    481      1.1  christos 
    482      1.1  christos     /* return end-of-file state */
    483      1.1  christos     return state->mode == GZ_READ ? state->past : 0;
    484      1.1  christos }
    485      1.1  christos 
    486      1.1  christos /* -- see zlib.h -- */
    487  1.1.1.3  christos const char * ZEXPORT gzerror(gzFile file, int *errnum) {
    488      1.1  christos     gz_statep state;
    489      1.1  christos 
    490      1.1  christos     /* get internal structure and check integrity */
    491      1.1  christos     if (file == NULL)
    492      1.1  christos         return NULL;
    493      1.1  christos     state = (gz_statep)file;
    494      1.1  christos     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    495      1.1  christos         return NULL;
    496      1.1  christos 
    497      1.1  christos     /* return error information */
    498      1.1  christos     if (errnum != NULL)
    499      1.1  christos         *errnum = state->err;
    500      1.1  christos     return state->err == Z_MEM_ERROR ? "out of memory" :
    501      1.1  christos                                        (state->msg == NULL ? "" : state->msg);
    502      1.1  christos }
    503      1.1  christos 
    504      1.1  christos /* -- see zlib.h -- */
    505  1.1.1.3  christos void ZEXPORT gzclearerr(gzFile file) {
    506      1.1  christos     gz_statep state;
    507      1.1  christos 
    508      1.1  christos     /* get internal structure and check integrity */
    509      1.1  christos     if (file == NULL)
    510      1.1  christos         return;
    511      1.1  christos     state = (gz_statep)file;
    512      1.1  christos     if (state->mode != GZ_READ && state->mode != GZ_WRITE)
    513      1.1  christos         return;
    514      1.1  christos 
    515      1.1  christos     /* clear error and end-of-file */
    516      1.1  christos     if (state->mode == GZ_READ) {
    517      1.1  christos         state->eof = 0;
    518      1.1  christos         state->past = 0;
    519      1.1  christos     }
    520      1.1  christos     gz_error(state, Z_OK, NULL);
    521      1.1  christos }
    522      1.1  christos 
    523      1.1  christos /* Create an error message in allocated memory and set state->err and
    524      1.1  christos    state->msg accordingly.  Free any previous error message already there.  Do
    525      1.1  christos    not try to free or allocate space if the error is Z_MEM_ERROR (out of
    526      1.1  christos    memory).  Simply save the error message as a static string.  If there is an
    527      1.1  christos    allocation failure constructing the error message, then convert the error to
    528      1.1  christos    out of memory. */
    529  1.1.1.3  christos void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
    530      1.1  christos     /* free previously allocated message and clear */
    531      1.1  christos     if (state->msg != NULL) {
    532      1.1  christos         if (state->err != Z_MEM_ERROR)
    533      1.1  christos             free(state->msg);
    534      1.1  christos         state->msg = NULL;
    535      1.1  christos     }
    536      1.1  christos 
    537      1.1  christos     /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
    538      1.1  christos     if (err != Z_OK && err != Z_BUF_ERROR)
    539      1.1  christos         state->x.have = 0;
    540      1.1  christos 
    541      1.1  christos     /* set error code, and if no message, then done */
    542      1.1  christos     state->err = err;
    543      1.1  christos     if (msg == NULL)
    544      1.1  christos         return;
    545      1.1  christos 
    546      1.1  christos     /* for an out of memory error, return literal string when requested */
    547      1.1  christos     if (err == Z_MEM_ERROR)
    548      1.1  christos         return;
    549      1.1  christos 
    550      1.1  christos     /* construct error message with path */
    551      1.1  christos     if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
    552      1.1  christos             NULL) {
    553      1.1  christos         state->err = Z_MEM_ERROR;
    554      1.1  christos         return;
    555      1.1  christos     }
    556      1.1  christos #if !defined(NO_snprintf) && !defined(NO_vsnprintf)
    557      1.1  christos     (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
    558      1.1  christos                    "%s%s%s", state->path, ": ", msg);
    559      1.1  christos #else
    560      1.1  christos     strcpy(state->msg, state->path);
    561      1.1  christos     strcat(state->msg, ": ");
    562      1.1  christos     strcat(state->msg, msg);
    563      1.1  christos #endif
    564      1.1  christos }
    565      1.1  christos 
    566      1.1  christos /* portably return maximum value for an int (when limits.h presumed not
    567      1.1  christos    available) -- we need to do this to cover cases where 2's complement not
    568      1.1  christos    used, since C standard permits 1's complement and sign-bit representations,
    569      1.1  christos    otherwise we could just use ((unsigned)-1) >> 1 */
    570  1.1.1.3  christos unsigned ZLIB_INTERNAL gz_intmax(void) {
    571  1.1.1.3  christos #ifdef INT_MAX
    572  1.1.1.3  christos     return INT_MAX;
    573  1.1.1.3  christos #else
    574  1.1.1.3  christos     unsigned p = 1, q;
    575      1.1  christos     do {
    576      1.1  christos         q = p;
    577      1.1  christos         p <<= 1;
    578      1.1  christos         p++;
    579      1.1  christos     } while (p > q);
    580      1.1  christos     return q >> 1;
    581      1.1  christos #endif
    582  1.1.1.3  christos }
    583