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