tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gzlib.c (16270B)


      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 }