tor-browser

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

gzwrite.c (19237B)


      1 /* gzwrite.c -- zlib functions for 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 /* Initialize state for writing a gzip file.  Mark initialization by setting
      9   state->size to non-zero.  Return -1 on a memory allocation failure, or 0 on
     10   success. */
     11 local int gz_init(gz_statep state) {
     12    int ret;
     13    z_streamp strm = &(state->strm);
     14 
     15    /* allocate input buffer (double size for gzprintf) */
     16    state->in = (unsigned char *)malloc(state->want << 1);
     17    if (state->in == NULL) {
     18        gz_error(state, Z_MEM_ERROR, "out of memory");
     19        return -1;
     20    }
     21 
     22    /* only need output buffer and deflate state if compressing */
     23    if (!state->direct) {
     24        /* allocate output buffer */
     25        state->out = (unsigned char *)malloc(state->want);
     26        if (state->out == NULL) {
     27            free(state->in);
     28            gz_error(state, Z_MEM_ERROR, "out of memory");
     29            return -1;
     30        }
     31 
     32        /* allocate deflate memory, set up for gzip compression */
     33        strm->zalloc = Z_NULL;
     34        strm->zfree = Z_NULL;
     35        strm->opaque = Z_NULL;
     36        ret = deflateInit2(strm, state->level, Z_DEFLATED,
     37                           MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
     38        if (ret != Z_OK) {
     39            free(state->out);
     40            free(state->in);
     41            gz_error(state, Z_MEM_ERROR, "out of memory");
     42            return -1;
     43        }
     44        strm->next_in = NULL;
     45    }
     46 
     47    /* mark state as initialized */
     48    state->size = state->want;
     49 
     50    /* initialize write buffer if compressing */
     51    if (!state->direct) {
     52        strm->avail_out = state->size;
     53        strm->next_out = state->out;
     54        state->x.next = strm->next_out;
     55    }
     56    return 0;
     57 }
     58 
     59 /* Compress whatever is at avail_in and next_in and write to the output file.
     60   Return -1 if there is an error writing to the output file or if gz_init()
     61   fails to allocate memory, otherwise 0.  flush is assumed to be a valid
     62   deflate() flush value.  If flush is Z_FINISH, then the deflate() state is
     63   reset to start a new gzip stream.  If gz->direct is true, then simply write
     64   to the output file without compressing, and ignore flush. */
     65 local int gz_comp(gz_statep state, int flush) {
     66    int ret, writ;
     67    unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
     68    z_streamp strm = &(state->strm);
     69 
     70    /* allocate memory if this is the first time through */
     71    if (state->size == 0 && gz_init(state) == -1)
     72        return -1;
     73 
     74    /* write directly if requested */
     75    if (state->direct) {
     76        while (strm->avail_in) {
     77            put = strm->avail_in > max ? max : strm->avail_in;
     78            writ = write(state->fd, strm->next_in, put);
     79            if (writ < 0) {
     80                gz_error(state, Z_ERRNO, zstrerror());
     81                return -1;
     82            }
     83            strm->avail_in -= (unsigned)writ;
     84            strm->next_in += writ;
     85        }
     86        return 0;
     87    }
     88 
     89    /* check for a pending reset */
     90    if (state->reset) {
     91        /* don't start a new gzip member unless there is data to write */
     92        if (strm->avail_in == 0)
     93            return 0;
     94        deflateReset(strm);
     95        state->reset = 0;
     96    }
     97 
     98    /* run deflate() on provided input until it produces no more output */
     99    ret = Z_OK;
    100    do {
    101        /* write out current buffer contents if full, or if flushing, but if
    102           doing Z_FINISH then don't write until we get to Z_STREAM_END */
    103        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
    104            (flush != Z_FINISH || ret == Z_STREAM_END))) {
    105            while (strm->next_out > state->x.next) {
    106                put = strm->next_out - state->x.next > (int)max ? max :
    107                      (unsigned)(strm->next_out - state->x.next);
    108                writ = write(state->fd, state->x.next, put);
    109                if (writ < 0) {
    110                    gz_error(state, Z_ERRNO, zstrerror());
    111                    return -1;
    112                }
    113                state->x.next += writ;
    114            }
    115            if (strm->avail_out == 0) {
    116                strm->avail_out = state->size;
    117                strm->next_out = state->out;
    118                state->x.next = state->out;
    119            }
    120        }
    121 
    122        /* compress */
    123        have = strm->avail_out;
    124        ret = deflate(strm, flush);
    125        if (ret == Z_STREAM_ERROR) {
    126            gz_error(state, Z_STREAM_ERROR,
    127                      "internal error: deflate stream corrupt");
    128            return -1;
    129        }
    130        have -= strm->avail_out;
    131    } while (have);
    132 
    133    /* if that completed a deflate stream, allow another to start */
    134    if (flush == Z_FINISH)
    135        state->reset = 1;
    136 
    137    /* all done, no errors */
    138    return 0;
    139 }
    140 
    141 /* Compress len zeros to output.  Return -1 on a write error or memory
    142   allocation failure by gz_comp(), or 0 on success. */
    143 local int gz_zero(gz_statep state, z_off64_t len) {
    144    int first;
    145    unsigned n;
    146    z_streamp strm = &(state->strm);
    147 
    148    /* consume whatever's left in the input buffer */
    149    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
    150        return -1;
    151 
    152    /* compress len zeros (len guaranteed > 0) */
    153    first = 1;
    154    while (len) {
    155        n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
    156            (unsigned)len : state->size;
    157        if (first) {
    158            memset(state->in, 0, n);
    159            first = 0;
    160        }
    161        strm->avail_in = n;
    162        strm->next_in = state->in;
    163        state->x.pos += n;
    164        if (gz_comp(state, Z_NO_FLUSH) == -1)
    165            return -1;
    166        len -= n;
    167    }
    168    return 0;
    169 }
    170 
    171 /* Write len bytes from buf to file.  Return the number of bytes written.  If
    172   the returned value is less than len, then there was an error. */
    173 local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
    174    z_size_t put = len;
    175 
    176    /* if len is zero, avoid unnecessary operations */
    177    if (len == 0)
    178        return 0;
    179 
    180    /* allocate memory if this is the first time through */
    181    if (state->size == 0 && gz_init(state) == -1)
    182        return 0;
    183 
    184    /* check for seek request */
    185    if (state->seek) {
    186        state->seek = 0;
    187        if (gz_zero(state, state->skip) == -1)
    188            return 0;
    189    }
    190 
    191    /* for small len, copy to input buffer, otherwise compress directly */
    192    if (len < state->size) {
    193        /* copy to input buffer, compress when full */
    194        do {
    195            unsigned have, copy;
    196 
    197            if (state->strm.avail_in == 0)
    198                state->strm.next_in = state->in;
    199            have = (unsigned)((state->strm.next_in + state->strm.avail_in) -
    200                              state->in);
    201            copy = state->size - have;
    202            if (copy > len)
    203                copy = (unsigned)len;
    204            memcpy(state->in + have, buf, copy);
    205            state->strm.avail_in += copy;
    206            state->x.pos += copy;
    207            buf = (const char *)buf + copy;
    208            len -= copy;
    209            if (len && gz_comp(state, Z_NO_FLUSH) == -1)
    210                return 0;
    211        } while (len);
    212    }
    213    else {
    214        /* consume whatever's left in the input buffer */
    215        if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
    216            return 0;
    217 
    218        /* directly compress user buffer to file */
    219        state->strm.next_in = (z_const Bytef *)buf;
    220        do {
    221            unsigned n = (unsigned)-1;
    222            if (n > len)
    223                n = (unsigned)len;
    224            state->strm.avail_in = n;
    225            state->x.pos += n;
    226            if (gz_comp(state, Z_NO_FLUSH) == -1)
    227                return 0;
    228            len -= n;
    229        } while (len);
    230    }
    231 
    232    /* input was all buffered or compressed */
    233    return put;
    234 }
    235 
    236 /* -- see zlib.h -- */
    237 int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
    238    gz_statep state;
    239 
    240    /* get internal structure */
    241    if (file == NULL)
    242        return 0;
    243    state = (gz_statep)file;
    244 
    245    /* check that we're writing and that there's no error */
    246    if (state->mode != GZ_WRITE || state->err != Z_OK)
    247        return 0;
    248 
    249    /* since an int is returned, make sure len fits in one, otherwise return
    250       with an error (this avoids a flaw in the interface) */
    251    if ((int)len < 0) {
    252        gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
    253        return 0;
    254    }
    255 
    256    /* write len bytes from buf (the return value will fit in an int) */
    257    return (int)gz_write(state, buf, len);
    258 }
    259 
    260 /* -- see zlib.h -- */
    261 z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
    262                          gzFile file) {
    263    z_size_t len;
    264    gz_statep state;
    265 
    266    /* get internal structure */
    267    if (file == NULL)
    268        return 0;
    269    state = (gz_statep)file;
    270 
    271    /* check that we're writing and that there's no error */
    272    if (state->mode != GZ_WRITE || state->err != Z_OK)
    273        return 0;
    274 
    275    /* compute bytes to read -- error on overflow */
    276    len = nitems * size;
    277    if (size && len / size != nitems) {
    278        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
    279        return 0;
    280    }
    281 
    282    /* write len bytes to buf, return the number of full items written */
    283    return len ? gz_write(state, buf, len) / size : 0;
    284 }
    285 
    286 /* -- see zlib.h -- */
    287 int ZEXPORT gzputc(gzFile file, int c) {
    288    unsigned have;
    289    unsigned char buf[1];
    290    gz_statep state;
    291    z_streamp strm;
    292 
    293    /* get internal structure */
    294    if (file == NULL)
    295        return -1;
    296    state = (gz_statep)file;
    297    strm = &(state->strm);
    298 
    299    /* check that we're writing and that there's no error */
    300    if (state->mode != GZ_WRITE || state->err != Z_OK)
    301        return -1;
    302 
    303    /* check for seek request */
    304    if (state->seek) {
    305        state->seek = 0;
    306        if (gz_zero(state, state->skip) == -1)
    307            return -1;
    308    }
    309 
    310    /* try writing to input buffer for speed (state->size == 0 if buffer not
    311       initialized) */
    312    if (state->size) {
    313        if (strm->avail_in == 0)
    314            strm->next_in = state->in;
    315        have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
    316        if (have < state->size) {
    317            state->in[have] = (unsigned char)c;
    318            strm->avail_in++;
    319            state->x.pos++;
    320            return c & 0xff;
    321        }
    322    }
    323 
    324    /* no room in buffer or not initialized, use gz_write() */
    325    buf[0] = (unsigned char)c;
    326    if (gz_write(state, buf, 1) != 1)
    327        return -1;
    328    return c & 0xff;
    329 }
    330 
    331 /* -- see zlib.h -- */
    332 int ZEXPORT gzputs(gzFile file, const char *s) {
    333    z_size_t len, put;
    334    gz_statep state;
    335 
    336    /* get internal structure */
    337    if (file == NULL)
    338        return -1;
    339    state = (gz_statep)file;
    340 
    341    /* check that we're writing and that there's no error */
    342    if (state->mode != GZ_WRITE || state->err != Z_OK)
    343        return -1;
    344 
    345    /* write string */
    346    len = strlen(s);
    347    if ((int)len < 0 || (unsigned)len != len) {
    348        gz_error(state, Z_STREAM_ERROR, "string length does not fit in int");
    349        return -1;
    350    }
    351    put = gz_write(state, s, len);
    352    return put < len ? -1 : (int)len;
    353 }
    354 
    355 #if defined(STDC) || defined(Z_HAVE_STDARG_H)
    356 #include <stdarg.h>
    357 
    358 /* -- see zlib.h -- */
    359 int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
    360    int len;
    361    unsigned left;
    362    char *next;
    363    gz_statep state;
    364    z_streamp strm;
    365 
    366    /* get internal structure */
    367    if (file == NULL)
    368        return Z_STREAM_ERROR;
    369    state = (gz_statep)file;
    370    strm = &(state->strm);
    371 
    372    /* check that we're writing and that there's no error */
    373    if (state->mode != GZ_WRITE || state->err != Z_OK)
    374        return Z_STREAM_ERROR;
    375 
    376    /* make sure we have some buffer space */
    377    if (state->size == 0 && gz_init(state) == -1)
    378        return state->err;
    379 
    380    /* check for seek request */
    381    if (state->seek) {
    382        state->seek = 0;
    383        if (gz_zero(state, state->skip) == -1)
    384            return state->err;
    385    }
    386 
    387    /* do the printf() into the input buffer, put length in len -- the input
    388       buffer is double-sized just for this function, so there is guaranteed to
    389       be state->size bytes available after the current contents */
    390    if (strm->avail_in == 0)
    391        strm->next_in = state->in;
    392    next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
    393    next[state->size - 1] = 0;
    394 #ifdef NO_vsnprintf
    395 #  ifdef HAS_vsprintf_void
    396    (void)vsprintf(next, format, va);
    397    for (len = 0; len < state->size; len++)
    398        if (next[len] == 0) break;
    399 #  else
    400    len = vsprintf(next, format, va);
    401 #  endif
    402 #else
    403 #  ifdef HAS_vsnprintf_void
    404    (void)vsnprintf(next, state->size, format, va);
    405    len = strlen(next);
    406 #  else
    407    len = vsnprintf(next, state->size, format, va);
    408 #  endif
    409 #endif
    410 
    411    /* check that printf() results fit in buffer */
    412    if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
    413        return 0;
    414 
    415    /* update buffer and position, compress first half if past that */
    416    strm->avail_in += (unsigned)len;
    417    state->x.pos += len;
    418    if (strm->avail_in >= state->size) {
    419        left = strm->avail_in - state->size;
    420        strm->avail_in = state->size;
    421        if (gz_comp(state, Z_NO_FLUSH) == -1)
    422            return state->err;
    423        memmove(state->in, state->in + state->size, left);
    424        strm->next_in = state->in;
    425        strm->avail_in = left;
    426    }
    427    return len;
    428 }
    429 
    430 int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
    431    va_list va;
    432    int ret;
    433 
    434    va_start(va, format);
    435    ret = gzvprintf(file, format, va);
    436    va_end(va);
    437    return ret;
    438 }
    439 
    440 #else /* !STDC && !Z_HAVE_STDARG_H */
    441 
    442 /* -- see zlib.h -- */
    443 int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
    444                       int a4, int a5, int a6, int a7, int a8, int a9, int a10,
    445                       int a11, int a12, int a13, int a14, int a15, int a16,
    446                       int a17, int a18, int a19, int a20) {
    447    unsigned len, left;
    448    char *next;
    449    gz_statep state;
    450    z_streamp strm;
    451 
    452    /* get internal structure */
    453    if (file == NULL)
    454        return Z_STREAM_ERROR;
    455    state = (gz_statep)file;
    456    strm = &(state->strm);
    457 
    458    /* check that can really pass pointer in ints */
    459    if (sizeof(int) != sizeof(void *))
    460        return Z_STREAM_ERROR;
    461 
    462    /* check that we're writing and that there's no error */
    463    if (state->mode != GZ_WRITE || state->err != Z_OK)
    464        return Z_STREAM_ERROR;
    465 
    466    /* make sure we have some buffer space */
    467    if (state->size == 0 && gz_init(state) == -1)
    468        return state->error;
    469 
    470    /* check for seek request */
    471    if (state->seek) {
    472        state->seek = 0;
    473        if (gz_zero(state, state->skip) == -1)
    474            return state->error;
    475    }
    476 
    477    /* do the printf() into the input buffer, put length in len -- the input
    478       buffer is double-sized just for this function, so there is guaranteed to
    479       be state->size bytes available after the current contents */
    480    if (strm->avail_in == 0)
    481        strm->next_in = state->in;
    482    next = (char *)(strm->next_in + strm->avail_in);
    483    next[state->size - 1] = 0;
    484 #ifdef NO_snprintf
    485 #  ifdef HAS_sprintf_void
    486    sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
    487            a13, a14, a15, a16, a17, a18, a19, a20);
    488    for (len = 0; len < size; len++)
    489        if (next[len] == 0)
    490            break;
    491 #  else
    492    len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
    493                  a12, a13, a14, a15, a16, a17, a18, a19, a20);
    494 #  endif
    495 #else
    496 #  ifdef HAS_snprintf_void
    497    snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,
    498             a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
    499    len = strlen(next);
    500 #  else
    501    len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,
    502                   a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
    503 #  endif
    504 #endif
    505 
    506    /* check that printf() results fit in buffer */
    507    if (len == 0 || len >= state->size || next[state->size - 1] != 0)
    508        return 0;
    509 
    510    /* update buffer and position, compress first half if past that */
    511    strm->avail_in += len;
    512    state->x.pos += len;
    513    if (strm->avail_in >= state->size) {
    514        left = strm->avail_in - state->size;
    515        strm->avail_in = state->size;
    516        if (gz_comp(state, Z_NO_FLUSH) == -1)
    517            return state->err;
    518        memmove(state->in, state->in + state->size, left);
    519        strm->next_in = state->in;
    520        strm->avail_in = left;
    521    }
    522    return (int)len;
    523 }
    524 
    525 #endif
    526 
    527 /* -- see zlib.h -- */
    528 int ZEXPORT gzflush(gzFile file, int flush) {
    529    gz_statep state;
    530 
    531    /* get internal structure */
    532    if (file == NULL)
    533        return Z_STREAM_ERROR;
    534    state = (gz_statep)file;
    535 
    536    /* check that we're writing and that there's no error */
    537    if (state->mode != GZ_WRITE || state->err != Z_OK)
    538        return Z_STREAM_ERROR;
    539 
    540    /* check flush parameter */
    541    if (flush < 0 || flush > Z_FINISH)
    542        return Z_STREAM_ERROR;
    543 
    544    /* check for seek request */
    545    if (state->seek) {
    546        state->seek = 0;
    547        if (gz_zero(state, state->skip) == -1)
    548            return state->err;
    549    }
    550 
    551    /* compress remaining data with requested flush */
    552    (void)gz_comp(state, flush);
    553    return state->err;
    554 }
    555 
    556 /* -- see zlib.h -- */
    557 int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
    558    gz_statep state;
    559    z_streamp strm;
    560 
    561    /* get internal structure */
    562    if (file == NULL)
    563        return Z_STREAM_ERROR;
    564    state = (gz_statep)file;
    565    strm = &(state->strm);
    566 
    567    /* check that we're writing and that there's no error */
    568    if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)
    569        return Z_STREAM_ERROR;
    570 
    571    /* if no change is requested, then do nothing */
    572    if (level == state->level && strategy == state->strategy)
    573        return Z_OK;
    574 
    575    /* check for seek request */
    576    if (state->seek) {
    577        state->seek = 0;
    578        if (gz_zero(state, state->skip) == -1)
    579            return state->err;
    580    }
    581 
    582    /* change compression parameters for subsequent input */
    583    if (state->size) {
    584        /* flush previous input with previous parameters before changing */
    585        if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
    586            return state->err;
    587        deflateParams(strm, level, strategy);
    588    }
    589    state->level = level;
    590    state->strategy = strategy;
    591    return Z_OK;
    592 }
    593 
    594 /* -- see zlib.h -- */
    595 int ZEXPORT gzclose_w(gzFile file) {
    596    int ret = Z_OK;
    597    gz_statep state;
    598 
    599    /* get internal structure */
    600    if (file == NULL)
    601        return Z_STREAM_ERROR;
    602    state = (gz_statep)file;
    603 
    604    /* check that we're writing */
    605    if (state->mode != GZ_WRITE)
    606        return Z_STREAM_ERROR;
    607 
    608    /* check for seek request */
    609    if (state->seek) {
    610        state->seek = 0;
    611        if (gz_zero(state, state->skip) == -1)
    612            ret = state->err;
    613    }
    614 
    615    /* flush, free memory, and close file */
    616    if (gz_comp(state, Z_FINISH) == -1)
    617        ret = state->err;
    618    if (state->size) {
    619        if (!state->direct) {
    620            (void)deflateEnd(&(state->strm));
    621            free(state->out);
    622        }
    623        free(state->in);
    624    }
    625    gz_error(state, Z_OK, NULL);
    626    free(state->path);
    627    if (close(state->fd) == -1)
    628        ret = Z_ERRNO;
    629    free(state);
    630    return ret;
    631 }