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