Home | History | Annotate | Line # | Download | only in zlibWrapper
gzwrite.c revision 1.1.1.1
      1 /* gzwrite.c contains minimal changes required to be compiled with zlibWrapper:
      2  * - gz_statep was converted to union to work with -Wstrict-aliasing=1      */
      3 
      4  /* gzwrite.c -- zlib functions for writing gzip files
      5  * Copyright (C) 2004-2017 Mark Adler
      6  * For conditions of distribution and use, see https://www.zlib.net/zlib_license.html
      7  */
      8 
      9 #include <assert.h>
     10 
     11 #include "gzguts.h"
     12 
     13 /* Local functions */
     14 local int gz_init _Z_OF((gz_statep));
     15 local int gz_comp _Z_OF((gz_statep, int));
     16 local int gz_zero _Z_OF((gz_statep, z_off64_t));
     17 local z_size_t gz_write _Z_OF((gz_statep, voidpc, z_size_t));
     18 
     19 /* Initialize state for writing a gzip file.  Mark initialization by setting
     20    state.state->size to non-zero.  Return -1 on a memory allocation failure, or 0 on
     21    success. */
     22 local int gz_init(gz_statep state) {
     23     int ret;
     24     z_streamp strm = &(state.state->strm);
     25 
     26     /* allocate input buffer (double size for gzprintf) */
     27     state.state->in = (unsigned char*)malloc(state.state->want << 1);
     28     if (state.state->in == NULL) {
     29         gz_error(state, Z_MEM_ERROR, "out of memory");
     30         return -1;
     31     }
     32 
     33     /* only need output buffer and deflate state if compressing */
     34     if (!state.state->direct) {
     35         /* allocate output buffer */
     36         state.state->out = (unsigned char*)malloc(state.state->want);
     37         if (state.state->out == NULL) {
     38             free(state.state->in);
     39             gz_error(state, Z_MEM_ERROR, "out of memory");
     40             return -1;
     41         }
     42 
     43         /* allocate deflate memory, set up for gzip compression */
     44         strm->zalloc = Z_NULL;
     45         strm->zfree = Z_NULL;
     46         strm->opaque = Z_NULL;
     47         ret = deflateInit2(strm, state.state->level, Z_DEFLATED,
     48                            MAX_WBITS + 16, DEF_MEM_LEVEL, state.state->strategy);
     49         if (ret != Z_OK) {
     50             free(state.state->out);
     51             free(state.state->in);
     52             gz_error(state, Z_MEM_ERROR, "out of memory");
     53             return -1;
     54         }
     55         strm->next_in = NULL;
     56     }
     57 
     58     /* mark state as initialized */
     59     state.state->size = state.state->want;
     60 
     61     /* initialize write buffer if compressing */
     62     if (!state.state->direct) {
     63         strm->avail_out = state.state->size;
     64         strm->next_out = state.state->out;
     65         state.state->x.next = strm->next_out;
     66     }
     67     return 0;
     68 }
     69 
     70 /* Compress whatever is at avail_in and next_in and write to the output file.
     71    Return -1 if there is an error writing to the output file or if gz_init()
     72    fails to allocate memory, otherwise 0.  flush is assumed to be a valid
     73    deflate() flush value.  If flush is Z_FINISH, then the deflate() state is
     74    reset to start a new gzip stream.  If gz->direct is true, then simply write
     75    to the output file without compressing, and ignore flush. */
     76 local int gz_comp(gz_statep state, int flush) {
     77     int ret, writ;
     78     unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
     79     z_streamp strm = &(state.state->strm);
     80 
     81     /* allocate memory if this is the first time through */
     82     if (state.state->size == 0 && gz_init(state) == -1)
     83         return -1;
     84 
     85     /* write directly if requested */
     86     if (state.state->direct) {
     87         while (strm->avail_in) {
     88             put = strm->avail_in > max ? max : strm->avail_in;
     89             writ = (int)write(state.state->fd, strm->next_in, put);
     90             if (writ < 0) {
     91                 gz_error(state, Z_ERRNO, zstrerror());
     92                 return -1;
     93             }
     94             strm->avail_in -= (unsigned)writ;
     95             strm->next_in += writ;
     96         }
     97         return 0;
     98     }
     99 
    100     /* run deflate() on provided input until it produces no more output */
    101     ret = Z_OK;
    102     do {
    103         /* write out current buffer contents if full, or if flushing, but if
    104            doing Z_FINISH then don't write until we get to Z_STREAM_END */
    105         if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
    106             (flush != Z_FINISH || ret == Z_STREAM_END))) {
    107             while (strm->next_out > state.state->x.next) {
    108                 put = strm->next_out - state.state->x.next > (int)max ? max :
    109                       (unsigned)(strm->next_out - state.state->x.next);
    110                 writ = (int)write(state.state->fd, state.state->x.next, put);
    111                 if (writ < 0) {
    112                     gz_error(state, Z_ERRNO, zstrerror());
    113                     return -1;
    114                 }
    115                 state.state->x.next += writ;
    116             }
    117             if (strm->avail_out == 0) {
    118                 strm->avail_out = state.state->size;
    119                 strm->next_out = state.state->out;
    120                 state.state->x.next = state.state->out;
    121             }
    122         }
    123 
    124         /* compress */
    125         have = strm->avail_out;
    126         ret = deflate(strm, flush);
    127         if (ret == Z_STREAM_ERROR) {
    128             gz_error(state, Z_STREAM_ERROR,
    129                       "internal error: deflate stream corrupt");
    130             return -1;
    131         }
    132         have -= strm->avail_out;
    133     } while (have);
    134 
    135     /* if that completed a deflate stream, allow another to start */
    136     if (flush == Z_FINISH)
    137         deflateReset(strm);
    138 
    139     /* all done, no errors */
    140     return 0;
    141 }
    142 
    143 /* Compress len zeros to output.  Return -1 on a write error or memory
    144    allocation failure by gz_comp(), or 0 on success. */
    145 local int gz_zero(gz_statep state, z_off64_t len) {
    146     int first;
    147     unsigned n;
    148     z_streamp strm = &(state.state->strm);
    149 
    150     /* consume whatever's left in the input buffer */
    151     if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
    152         return -1;
    153 
    154     /* compress len zeros (len guaranteed > 0) */
    155     first = 1;
    156     while (len) {
    157         n = GT_OFF(state.state->size) || (z_off64_t)state.state->size > len ?
    158             (unsigned)len : state.state->size;
    159         if (first) {
    160             memset(state.state->in, 0, n);
    161             first = 0;
    162         }
    163         strm->avail_in = n;
    164         strm->next_in = state.state->in;
    165         state.state->x.pos += n;
    166         if (gz_comp(state, Z_NO_FLUSH) == -1)
    167             return -1;
    168         len -= n;
    169     }
    170     return 0;
    171 }
    172 
    173 /* Write len bytes from buf to file.  Return the number of bytes written.  If
    174    the returned value is less than len, then there was an error. */
    175 local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
    176     z_size_t put = len;
    177 
    178     /* if len is zero, avoid unnecessary operations */
    179     if (len == 0)
    180         return 0;
    181 
    182     /* allocate memory if this is the first time through */
    183     if (state.state->size == 0 && gz_init(state) == -1)
    184         return 0;
    185 
    186     /* check for seek request */
    187     if (state.state->seek) {
    188         state.state->seek = 0;
    189         if (gz_zero(state, state.state->skip) == -1)
    190             return 0;
    191     }
    192 
    193     /* for small len, copy to input buffer, otherwise compress directly */
    194     if (len < state.state->size) {
    195         /* copy to input buffer, compress when full */
    196         do {
    197             z_size_t have, copy;
    198 
    199             if (state.state->strm.avail_in == 0)
    200                 state.state->strm.next_in = state.state->in;
    201             have = (unsigned)((state.state->strm.next_in + state.state->strm.avail_in) -
    202                               state.state->in);
    203             copy = state.state->size - have;
    204             if (copy > len)
    205                 copy = len;
    206             memcpy(state.state->in + have, buf, copy);
    207             state.state->strm.avail_in += copy;
    208             state.state->x.pos += copy;
    209             buf = (const char *)buf + copy;
    210             len -= copy;
    211             if (len && gz_comp(state, Z_NO_FLUSH) == -1)
    212                 return 0;
    213         } while (len);
    214     }
    215     else {
    216         /* consume whatever's left in the input buffer */
    217         if (state.state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
    218             return 0;
    219 
    220         /* directly compress user buffer to file */
    221         state.state->strm.next_in = (z_const Bytef *)buf;
    222         do {
    223             z_size_t n = (unsigned)-1;
    224             if (n > len)
    225                 n = len;
    226             state.state->strm.avail_in = (z_uInt)n;
    227             state.state->x.pos += n;
    228             if (gz_comp(state, Z_NO_FLUSH) == -1)
    229                 return 0;
    230             len -= n;
    231         } while (len);
    232     }
    233 
    234     /* input was all buffered or compressed */
    235     return put;
    236 }
    237 
    238 /* -- see zlib.h -- */
    239 int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
    240     gz_statep state;
    241 
    242     /* get internal structure */
    243     if (file == NULL)
    244         return 0;
    245     state.file = file;
    246 
    247     /* check that we're writing and that there's no error */
    248     if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
    249         return 0;
    250 
    251     /* since an int is returned, make sure len fits in one, otherwise return
    252        with an error (this avoids a flaw in the interface) */
    253     if ((int)len < 0) {
    254         gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
    255         return 0;
    256     }
    257 
    258     /* write len bytes from buf (the return value will fit in an int) */
    259     return (int)gz_write(state, buf, len);
    260 }
    261 
    262 /* -- see zlib.h -- */
    263 z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
    264                           gzFile file) {
    265     z_size_t len;
    266     gz_statep state;
    267 
    268     /* get internal structure */
    269     assert(size != 0);
    270     if (file == NULL)
    271         return 0;
    272     state.file = file;
    273 
    274     /* check that we're writing and that there's no error */
    275     if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
    276         return 0;
    277 
    278     /* compute bytes to read -- error on overflow */
    279     len = nitems * size;
    280     if (size && (len / size != nitems)) {
    281         gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
    282         return 0;
    283     }
    284 
    285     /* write len bytes to buf, return the number of full items written */
    286     return len ? gz_write(state, buf, len) / size : 0;
    287 }
    288 
    289 /* -- see zlib.h -- */
    290 int ZEXPORT gzputc(gzFile file, int c) {
    291     unsigned have;
    292     unsigned char buf[1];
    293     gz_statep state;
    294     z_streamp strm;
    295 
    296     /* get internal structure */
    297     if (file == NULL)
    298         return -1;
    299     state.file = file;
    300     strm = &(state.state->strm);
    301 
    302     /* check that we're writing and that there's no error */
    303     if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
    304         return -1;
    305 
    306     /* check for seek request */
    307     if (state.state->seek) {
    308         state.state->seek = 0;
    309         if (gz_zero(state, state.state->skip) == -1)
    310             return -1;
    311     }
    312 
    313     /* try writing to input buffer for speed (state.state->size == 0 if buffer not
    314        initialized) */
    315     if (state.state->size) {
    316         if (strm->avail_in == 0)
    317             strm->next_in = state.state->in;
    318         have = (unsigned)((strm->next_in + strm->avail_in) - state.state->in);
    319         if (have < state.state->size) {
    320             state.state->in[have] = (unsigned char)c;
    321             strm->avail_in++;
    322             state.state->x.pos++;
    323             return c & 0xff;
    324         }
    325     }
    326 
    327     /* no room in buffer or not initialized, use gz_write() */
    328     buf[0] = (unsigned char)c;
    329     if (gz_write(state, buf, 1) != 1)
    330         return -1;
    331     return c & 0xff;
    332 }
    333 
    334 /* -- see zlib.h -- */
    335 int ZEXPORT gzputs(gzFile file, const char *str) {
    336     int ret;
    337     z_size_t len;
    338     gz_statep state;
    339 
    340     /* get internal structure */
    341     if (file == NULL)
    342         return -1;
    343     state.file = file;
    344 
    345     /* check that we're writing and that there's no error */
    346     if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
    347         return -1;
    348 
    349     /* write string */
    350     len = strlen(str);
    351     ret = (int)gz_write(state, str, len);
    352     return ret == 0 && len != 0 ? -1 : ret;
    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.file = file;
    370     strm = &(state.state->strm);
    371 
    372     /* check that we're writing and that there's no error */
    373     if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
    374         return Z_STREAM_ERROR;
    375 
    376     /* make sure we have some buffer space */
    377     if (state.state->size == 0 && gz_init(state) == -1)
    378         return state.state->err;
    379 
    380     /* check for seek request */
    381     if (state.state->seek) {
    382         state.state->seek = 0;
    383         if (gz_zero(state, state.state->skip) == -1)
    384             return state.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.state->size bytes available after the current contents */
    390     if (strm->avail_in == 0)
    391         strm->next_in = state.state->in;
    392     next = (char *)(state.state->in + (strm->next_in - state.state->in) + strm->avail_in);
    393     next[state.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.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.state->size, format, va);
    405     len = strlen(next);
    406 #  else
    407     len = vsnprintf(next, state.state->size, format, va);
    408 #  endif
    409 #endif
    410 
    411     /* check that printf() results fit in buffer */
    412     if (len == 0 || (unsigned)len >= state.state->size || next[state.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.state->x.pos += len;
    418     if (strm->avail_in >= state.state->size) {
    419         left = strm->avail_in - state.state->size;
    420         strm->avail_in = state.state->size;
    421         if (gz_comp(state, Z_NO_FLUSH) == -1)
    422             return state.state->err;
    423         memcpy(state.state->in, state.state->in + state.state->size, left);
    424         strm->next_in = state.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.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.state->mode != GZ_WRITE || state.state->err != Z_OK)
    464         return Z_STREAM_ERROR;
    465 
    466     /* make sure we have some buffer space */
    467     if (state.state->size == 0 && gz_init(state) == -1)
    468         return state.state->error;
    469 
    470     /* check for seek request */
    471     if (state.state->seek) {
    472         state.state->seek = 0;
    473         if (gz_zero(state, state.state->skip) == -1)
    474             return state.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.state->size bytes available after the current contents */
    480     if (strm->avail_in == 0)
    481         strm->next_in = state.state->in;
    482     next = (char *)(strm->next_in + strm->avail_in);
    483     next[state.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.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.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.state->size || next[state.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.state->x.pos += len;
    513     if (strm->avail_in >= state.state->size) {
    514         left = strm->avail_in - state.state->size;
    515         strm->avail_in = state.state->size;
    516         if (gz_comp(state, Z_NO_FLUSH) == -1)
    517             return state.state->err;
    518         memcpy(state.state->in, state.state->in + state.state->size, left);
    519         strm->next_in = state.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.file = file;
    535 
    536     /* check that we're writing and that there's no error */
    537     if (state.state->mode != GZ_WRITE || state.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.state->seek) {
    546         state.state->seek = 0;
    547         if (gz_zero(state, state.state->skip) == -1)
    548             return state.state->err;
    549     }
    550 
    551     /* compress remaining data with requested flush */
    552     (void)gz_comp(state, flush);
    553     return state.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.file = file;
    565     strm = &(state.state->strm);
    566 
    567     /* check that we're writing and that there's no error */
    568     if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)
    569         return Z_STREAM_ERROR;
    570 
    571     /* if no change is requested, then do nothing */
    572     if (level == state.state->level && strategy == state.state->strategy)
    573         return Z_OK;
    574 
    575     /* check for seek request */
    576     if (state.state->seek) {
    577         state.state->seek = 0;
    578         if (gz_zero(state, state.state->skip) == -1)
    579             return state.state->err;
    580     }
    581 
    582     /* change compression parameters for subsequent input */
    583     if (state.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.state->err;
    587         deflateParams(strm, level, strategy);
    588     }
    589     state.state->level = level;
    590     state.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.file = file;
    603 
    604     /* check that we're writing */
    605     if (state.state->mode != GZ_WRITE)
    606         return Z_STREAM_ERROR;
    607 
    608     /* check for seek request */
    609     if (state.state->seek) {
    610         state.state->seek = 0;
    611         if (gz_zero(state, state.state->skip) == -1)
    612             ret = state.state->err;
    613     }
    614 
    615     /* flush, free memory, and close file */
    616     if (gz_comp(state, Z_FINISH) == -1)
    617         ret = state.state->err;
    618     if (state.state->size) {
    619         if (!state.state->direct) {
    620             (void)deflateEnd(&(state.state->strm));
    621             free(state.state->out);
    622         }
    623         free(state.state->in);
    624     }
    625     gz_error(state, Z_OK, NULL);
    626     free(state.state->path);
    627     if (close(state.state->fd) == -1)
    628         ret = Z_ERRNO;
    629     free(state.state);
    630     return ret;
    631 }
    632