Path: blob/main/sys/contrib/zstd/zlibWrapper/gzwrite.c
48254 views
/* gzwrite.c contains minimal changes required to be compiled with zlibWrapper:1* - gz_statep was converted to union to work with -Wstrict-aliasing=1 */23/* gzwrite.c -- zlib functions for writing gzip files4* Copyright (C) 2004-2017 Mark Adler5* For conditions of distribution and use, see http://www.zlib.net/zlib_license.html6*/78#include <assert.h>910#include "gzguts.h"1112/* Local functions */13local int gz_init OF((gz_statep));14local int gz_comp OF((gz_statep, int));15local int gz_zero OF((gz_statep, z_off64_t));16local z_size_t gz_write OF((gz_statep, voidpc, z_size_t));1718/* Initialize state for writing a gzip file. Mark initialization by setting19state.state->size to non-zero. Return -1 on a memory allocation failure, or 0 on20success. */21local int gz_init(state)22gz_statep state;23{24int ret;25z_streamp strm = &(state.state->strm);2627/* allocate input buffer (double size for gzprintf) */28state.state->in = (unsigned char*)malloc(state.state->want << 1);29if (state.state->in == NULL) {30gz_error(state, Z_MEM_ERROR, "out of memory");31return -1;32}3334/* only need output buffer and deflate state if compressing */35if (!state.state->direct) {36/* allocate output buffer */37state.state->out = (unsigned char*)malloc(state.state->want);38if (state.state->out == NULL) {39free(state.state->in);40gz_error(state, Z_MEM_ERROR, "out of memory");41return -1;42}4344/* allocate deflate memory, set up for gzip compression */45strm->zalloc = Z_NULL;46strm->zfree = Z_NULL;47strm->opaque = Z_NULL;48ret = deflateInit2(strm, state.state->level, Z_DEFLATED,49MAX_WBITS + 16, DEF_MEM_LEVEL, state.state->strategy);50if (ret != Z_OK) {51free(state.state->out);52free(state.state->in);53gz_error(state, Z_MEM_ERROR, "out of memory");54return -1;55}56strm->next_in = NULL;57}5859/* mark state as initialized */60state.state->size = state.state->want;6162/* initialize write buffer if compressing */63if (!state.state->direct) {64strm->avail_out = state.state->size;65strm->next_out = state.state->out;66state.state->x.next = strm->next_out;67}68return 0;69}7071/* Compress whatever is at avail_in and next_in and write to the output file.72Return -1 if there is an error writing to the output file or if gz_init()73fails to allocate memory, otherwise 0. flush is assumed to be a valid74deflate() flush value. If flush is Z_FINISH, then the deflate() state is75reset to start a new gzip stream. If gz->direct is true, then simply write76to the output file without compressing, and ignore flush. */77local int gz_comp(state, flush)78gz_statep state;79int flush;80{81int ret, writ;82unsigned have, put, max = ((unsigned)-1 >> 2) + 1;83z_streamp strm = &(state.state->strm);8485/* allocate memory if this is the first time through */86if (state.state->size == 0 && gz_init(state) == -1)87return -1;8889/* write directly if requested */90if (state.state->direct) {91while (strm->avail_in) {92put = strm->avail_in > max ? max : strm->avail_in;93writ = (int)write(state.state->fd, strm->next_in, put);94if (writ < 0) {95gz_error(state, Z_ERRNO, zstrerror());96return -1;97}98strm->avail_in -= (unsigned)writ;99strm->next_in += writ;100}101return 0;102}103104/* 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 &&110(flush != Z_FINISH || ret == Z_STREAM_END))) {111while (strm->next_out > state.state->x.next) {112put = strm->next_out - state.state->x.next > (int)max ? max :113(unsigned)(strm->next_out - state.state->x.next);114writ = (int)write(state.state->fd, state.state->x.next, put);115if (writ < 0) {116gz_error(state, Z_ERRNO, zstrerror());117return -1;118}119state.state->x.next += writ;120}121if (strm->avail_out == 0) {122strm->avail_out = state.state->size;123strm->next_out = state.state->out;124state.state->x.next = state.state->out;125}126}127128/* compress */129have = strm->avail_out;130ret = deflate(strm, flush);131if (ret == Z_STREAM_ERROR) {132gz_error(state, Z_STREAM_ERROR,133"internal error: deflate stream corrupt");134return -1;135}136have -= strm->avail_out;137} while (have);138139/* if that completed a deflate stream, allow another to start */140if (flush == Z_FINISH)141deflateReset(strm);142143/* all done, no errors */144return 0;145}146147/* Compress len zeros to output. Return -1 on a write error or memory148allocation failure by gz_comp(), or 0 on success. */149local int gz_zero(state, len)150gz_statep state;151z_off64_t len;152{153int first;154unsigned n;155z_streamp strm = &(state.state->strm);156157/* consume whatever's left in the input buffer */158if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)159return -1;160161/* compress len zeros (len guaranteed > 0) */162first = 1;163while (len) {164n = GT_OFF(state.state->size) || (z_off64_t)state.state->size > len ?165(unsigned)len : state.state->size;166if (first) {167memset(state.state->in, 0, n);168first = 0;169}170strm->avail_in = n;171strm->next_in = state.state->in;172state.state->x.pos += n;173if (gz_comp(state, Z_NO_FLUSH) == -1)174return -1;175len -= n;176}177return 0;178}179180/* Write len bytes from buf to file. Return the number of bytes written. If181the returned value is less than len, then there was an error. */182local z_size_t gz_write(state, buf, len)183gz_statep state;184voidpc buf;185z_size_t len;186{187z_size_t put = len;188189/* if len is zero, avoid unnecessary operations */190if (len == 0)191return 0;192193/* allocate memory if this is the first time through */194if (state.state->size == 0 && gz_init(state) == -1)195return 0;196197/* check for seek request */198if (state.state->seek) {199state.state->seek = 0;200if (gz_zero(state, state.state->skip) == -1)201return 0;202}203204/* for small len, copy to input buffer, otherwise compress directly */205if (len < state.state->size) {206/* copy to input buffer, compress when full */207do {208z_size_t have, copy;209210if (state.state->strm.avail_in == 0)211state.state->strm.next_in = state.state->in;212have = (unsigned)((state.state->strm.next_in + state.state->strm.avail_in) -213state.state->in);214copy = state.state->size - have;215if (copy > len)216copy = len;217memcpy(state.state->in + have, buf, copy);218state.state->strm.avail_in += copy;219state.state->x.pos += copy;220buf = (const char *)buf + copy;221len -= copy;222if (len && gz_comp(state, Z_NO_FLUSH) == -1)223return 0;224} while (len);225}226else {227/* consume whatever's left in the input buffer */228if (state.state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)229return 0;230231/* directly compress user buffer to file */232state.state->strm.next_in = (z_const Bytef *)buf;233do {234z_size_t n = (unsigned)-1;235if (n > len)236n = len;237state.state->strm.avail_in = (z_uInt)n;238state.state->x.pos += n;239if (gz_comp(state, Z_NO_FLUSH) == -1)240return 0;241len -= n;242} while (len);243}244245/* input was all buffered or compressed */246return put;247}248249/* -- see zlib.h -- */250int ZEXPORT gzwrite(file, buf, len)251gzFile file;252voidpc buf;253unsigned len;254{255gz_statep state;256257/* get internal structure */258if (file == NULL)259return 0;260state.file = file;261262/* check that we're writing and that there's no error */263if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)264return 0;265266/* since an int is returned, make sure len fits in one, otherwise return267with an error (this avoids a flaw in the interface) */268if ((int)len < 0) {269gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");270return 0;271}272273/* write len bytes from buf (the return value will fit in an int) */274return (int)gz_write(state, buf, len);275}276277/* -- see zlib.h -- */278z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)279voidpc buf;280z_size_t size;281z_size_t nitems;282gzFile file;283{284z_size_t len;285gz_statep state;286287/* get internal structure */288assert(size != 0);289if (file == NULL)290return 0;291state.file = file;292293/* check that we're writing and that there's no error */294if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)295return 0;296297/* compute bytes to read -- error on overflow */298len = nitems * size;299if (size && (len / size != nitems)) {300gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");301return 0;302}303304/* write len bytes to buf, return the number of full items written */305return len ? gz_write(state, buf, len) / size : 0;306}307308/* -- see zlib.h -- */309int ZEXPORT gzputc(file, c)310gzFile file;311int c;312{313unsigned have;314unsigned char buf[1];315gz_statep state;316z_streamp strm;317318/* get internal structure */319if (file == NULL)320return -1;321state.file = file;322strm = &(state.state->strm);323324/* check that we're writing and that there's no error */325if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)326return -1;327328/* check for seek request */329if (state.state->seek) {330state.state->seek = 0;331if (gz_zero(state, state.state->skip) == -1)332return -1;333}334335/* try writing to input buffer for speed (state.state->size == 0 if buffer not336initialized) */337if (state.state->size) {338if (strm->avail_in == 0)339strm->next_in = state.state->in;340have = (unsigned)((strm->next_in + strm->avail_in) - state.state->in);341if (have < state.state->size) {342state.state->in[have] = (unsigned char)c;343strm->avail_in++;344state.state->x.pos++;345return c & 0xff;346}347}348349/* no room in buffer or not initialized, use gz_write() */350buf[0] = (unsigned char)c;351if (gz_write(state, buf, 1) != 1)352return -1;353return c & 0xff;354}355356/* -- see zlib.h -- */357int ZEXPORT gzputs(file, str)358gzFile file;359const char *str;360{361int ret;362z_size_t len;363gz_statep state;364365/* get internal structure */366if (file == NULL)367return -1;368state.file = file;369370/* check that we're writing and that there's no error */371if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)372return -1;373374/* write string */375len = strlen(str);376ret = (int)gz_write(state, str, len);377return ret == 0 && len != 0 ? -1 : ret;378}379380#if defined(STDC) || defined(Z_HAVE_STDARG_H)381#include <stdarg.h>382383/* -- see zlib.h -- */384int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)385{386int len;387unsigned left;388char *next;389gz_statep state;390z_streamp strm;391392/* get internal structure */393if (file == NULL)394return Z_STREAM_ERROR;395state.file = file;396strm = &(state.state->strm);397398/* check that we're writing and that there's no error */399if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)400return Z_STREAM_ERROR;401402/* make sure we have some buffer space */403if (state.state->size == 0 && gz_init(state) == -1)404return state.state->err;405406/* check for seek request */407if (state.state->seek) {408state.state->seek = 0;409if (gz_zero(state, state.state->skip) == -1)410return state.state->err;411}412413/* do the printf() into the input buffer, put length in len -- the input414buffer is double-sized just for this function, so there is guaranteed to415be state.state->size bytes available after the current contents */416if (strm->avail_in == 0)417strm->next_in = state.state->in;418next = (char *)(state.state->in + (strm->next_in - state.state->in) + strm->avail_in);419next[state.state->size - 1] = 0;420#ifdef NO_vsnprintf421# ifdef HAS_vsprintf_void422(void)vsprintf(next, format, va);423for (len = 0; len < state.state->size; len++)424if (next[len] == 0) break;425# else426len = vsprintf(next, format, va);427# endif428#else429# ifdef HAS_vsnprintf_void430(void)vsnprintf(next, state.state->size, format, va);431len = strlen(next);432# else433len = vsnprintf(next, state.state->size, format, va);434# endif435#endif436437/* check that printf() results fit in buffer */438if (len == 0 || (unsigned)len >= state.state->size || next[state.state->size - 1] != 0)439return 0;440441/* update buffer and position, compress first half if past that */442strm->avail_in += (unsigned)len;443state.state->x.pos += len;444if (strm->avail_in >= state.state->size) {445left = strm->avail_in - state.state->size;446strm->avail_in = state.state->size;447if (gz_comp(state, Z_NO_FLUSH) == -1)448return state.state->err;449memcpy(state.state->in, state.state->in + state.state->size, left);450strm->next_in = state.state->in;451strm->avail_in = left;452}453return len;454}455456int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)457{458va_list va;459int ret;460461va_start(va, format);462ret = gzvprintf(file, format, va);463va_end(va);464return ret;465}466467#else /* !STDC && !Z_HAVE_STDARG_H */468469/* -- see zlib.h -- */470int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,471a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)472gzFile file;473const char *format;474int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,475a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;476{477unsigned len, left;478char *next;479gz_statep state;480z_streamp strm;481482/* get internal structure */483if (file == NULL)484return Z_STREAM_ERROR;485state = (gz_statep)file;486strm = &(state.state->strm);487488/* check that can really pass pointer in ints */489if (sizeof(int) != sizeof(void *))490return Z_STREAM_ERROR;491492/* check that we're writing and that there's no error */493if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)494return Z_STREAM_ERROR;495496/* make sure we have some buffer space */497if (state.state->size == 0 && gz_init(state) == -1)498return state.state->error;499500/* check for seek request */501if (state.state->seek) {502state.state->seek = 0;503if (gz_zero(state, state.state->skip) == -1)504return state.state->error;505}506507/* do the printf() into the input buffer, put length in len -- the input508buffer is double-sized just for this function, so there is guaranteed to509be state.state->size bytes available after the current contents */510if (strm->avail_in == 0)511strm->next_in = state.state->in;512next = (char *)(strm->next_in + strm->avail_in);513next[state.state->size - 1] = 0;514#ifdef NO_snprintf515# ifdef HAS_sprintf_void516sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,517a13, a14, a15, a16, a17, a18, a19, a20);518for (len = 0; len < size; len++)519if (next[len] == 0)520break;521# else522len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,523a12, a13, a14, a15, a16, a17, a18, a19, a20);524# endif525#else526# ifdef HAS_snprintf_void527snprintf(next, state.state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,528a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);529len = strlen(next);530# else531len = snprintf(next, state.state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,532a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);533# endif534#endif535536/* check that printf() results fit in buffer */537if (len == 0 || len >= state.state->size || next[state.state->size - 1] != 0)538return 0;539540/* update buffer and position, compress first half if past that */541strm->avail_in += len;542state.state->x.pos += len;543if (strm->avail_in >= state.state->size) {544left = strm->avail_in - state.state->size;545strm->avail_in = state.state->size;546if (gz_comp(state, Z_NO_FLUSH) == -1)547return state.state->err;548memcpy(state.state->in, state.state->in + state.state->size, left);549strm->next_in = state.state->in;550strm->avail_in = left;551}552return (int)len;553}554555#endif556557/* -- see zlib.h -- */558int ZEXPORT gzflush(file, flush)559gzFile file;560int flush;561{562gz_statep state;563564/* get internal structure */565if (file == NULL)566return Z_STREAM_ERROR;567state.file = file;568569/* check that we're writing and that there's no error */570if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)571return Z_STREAM_ERROR;572573/* check flush parameter */574if (flush < 0 || flush > Z_FINISH)575return Z_STREAM_ERROR;576577/* check for seek request */578if (state.state->seek) {579state.state->seek = 0;580if (gz_zero(state, state.state->skip) == -1)581return state.state->err;582}583584/* compress remaining data with requested flush */585(void)gz_comp(state, flush);586return state.state->err;587}588589/* -- see zlib.h -- */590int ZEXPORT gzsetparams(file, level, strategy)591gzFile file;592int level;593int strategy;594{595gz_statep state;596z_streamp strm;597598/* get internal structure */599if (file == NULL)600return Z_STREAM_ERROR;601state.file = file;602strm = &(state.state->strm);603604/* check that we're writing and that there's no error */605if (state.state->mode != GZ_WRITE || state.state->err != Z_OK)606return Z_STREAM_ERROR;607608/* if no change is requested, then do nothing */609if (level == state.state->level && strategy == state.state->strategy)610return Z_OK;611612/* check for seek request */613if (state.state->seek) {614state.state->seek = 0;615if (gz_zero(state, state.state->skip) == -1)616return state.state->err;617}618619/* change compression parameters for subsequent input */620if (state.state->size) {621/* flush previous input with previous parameters before changing */622if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)623return state.state->err;624deflateParams(strm, level, strategy);625}626state.state->level = level;627state.state->strategy = strategy;628return Z_OK;629}630631/* -- see zlib.h -- */632int ZEXPORT gzclose_w(file)633gzFile file;634{635int ret = Z_OK;636gz_statep state;637638/* get internal structure */639if (file == NULL)640return Z_STREAM_ERROR;641state.file = file;642643/* check that we're writing */644if (state.state->mode != GZ_WRITE)645return Z_STREAM_ERROR;646647/* check for seek request */648if (state.state->seek) {649state.state->seek = 0;650if (gz_zero(state, state.state->skip) == -1)651ret = state.state->err;652}653654/* flush, free memory, and close file */655if (gz_comp(state, Z_FINISH) == -1)656ret = state.state->err;657if (state.state->size) {658if (!state.state->direct) {659(void)deflateEnd(&(state.state->strm));660free(state.state->out);661}662free(state.state->in);663}664gz_error(state, Z_OK, NULL);665free(state.state->path);666if (close(state.state->fd) == -1)667ret = Z_ERRNO;668free(state.state);669return ret;670}671672673