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