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