Path: blob/master/src/java.base/share/native/libzip/zlib/gzwrite.c
41153 views
/*1* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation. Oracle designates this6* particular file as subject to the "Classpath" exception as provided7* by Oracle in the LICENSE file that accompanied this code.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324/* gzwrite.c -- zlib functions for writing gzip files25* Copyright (C) 2004-2017 Mark Adler26* For conditions of distribution and use, see copyright notice in zlib.h27*/2829#include "gzguts.h"3031/* Local functions */32local int gz_init OF((gz_statep));33local int gz_comp OF((gz_statep, int));34local int gz_zero OF((gz_statep, z_off64_t));35local z_size_t gz_write OF((gz_statep, voidpc, z_size_t));3637/* Initialize state for writing a gzip file. Mark initialization by setting38state->size to non-zero. Return -1 on a memory allocation failure, or 0 on39success. */40local int gz_init(state)41gz_statep state;42{43int ret;44z_streamp strm = &(state->strm);4546/* allocate input buffer (double size for gzprintf) */47state->in = (unsigned char *)malloc(state->want << 1);48if (state->in == NULL) {49gz_error(state, Z_MEM_ERROR, "out of memory");50return -1;51}5253/* only need output buffer and deflate state if compressing */54if (!state->direct) {55/* allocate output buffer */56state->out = (unsigned char *)malloc(state->want);57if (state->out == NULL) {58free(state->in);59gz_error(state, Z_MEM_ERROR, "out of memory");60return -1;61}6263/* allocate deflate memory, set up for gzip compression */64strm->zalloc = Z_NULL;65strm->zfree = Z_NULL;66strm->opaque = Z_NULL;67ret = deflateInit2(strm, state->level, Z_DEFLATED,68MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);69if (ret != Z_OK) {70free(state->out);71free(state->in);72gz_error(state, Z_MEM_ERROR, "out of memory");73return -1;74}75strm->next_in = NULL;76}7778/* mark state as initialized */79state->size = state->want;8081/* initialize write buffer if compressing */82if (!state->direct) {83strm->avail_out = state->size;84strm->next_out = state->out;85state->x.next = strm->next_out;86}87return 0;88}8990/* Compress whatever is at avail_in and next_in and write to the output file.91Return -1 if there is an error writing to the output file or if gz_init()92fails to allocate memory, otherwise 0. flush is assumed to be a valid93deflate() flush value. If flush is Z_FINISH, then the deflate() state is94reset to start a new gzip stream. If gz->direct is true, then simply write95to the output file without compressing, and ignore flush. */96local int gz_comp(state, flush)97gz_statep state;98int flush;99{100int ret, writ;101unsigned have, put, max = ((unsigned)-1 >> 2) + 1;102z_streamp strm = &(state->strm);103104/* allocate memory if this is the first time through */105if (state->size == 0 && gz_init(state) == -1)106return -1;107108/* write directly if requested */109if (state->direct) {110while (strm->avail_in) {111put = strm->avail_in > max ? max : strm->avail_in;112writ = write(state->fd, strm->next_in, put);113if (writ < 0) {114gz_error(state, Z_ERRNO, zstrerror());115return -1;116}117strm->avail_in -= (unsigned)writ;118strm->next_in += writ;119}120return 0;121}122123/* run deflate() on provided input until it produces no more output */124ret = Z_OK;125do {126/* write out current buffer contents if full, or if flushing, but if127doing Z_FINISH then don't write until we get to Z_STREAM_END */128if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&129(flush != Z_FINISH || ret == Z_STREAM_END))) {130while (strm->next_out > state->x.next) {131put = strm->next_out - state->x.next > (int)max ? max :132(unsigned)(strm->next_out - state->x.next);133writ = write(state->fd, state->x.next, put);134if (writ < 0) {135gz_error(state, Z_ERRNO, zstrerror());136return -1;137}138state->x.next += writ;139}140if (strm->avail_out == 0) {141strm->avail_out = state->size;142strm->next_out = state->out;143state->x.next = state->out;144}145}146147/* compress */148have = strm->avail_out;149ret = deflate(strm, flush);150if (ret == Z_STREAM_ERROR) {151gz_error(state, Z_STREAM_ERROR,152"internal error: deflate stream corrupt");153return -1;154}155have -= strm->avail_out;156} while (have);157158/* if that completed a deflate stream, allow another to start */159if (flush == Z_FINISH)160deflateReset(strm);161162/* all done, no errors */163return 0;164}165166/* Compress len zeros to output. Return -1 on a write error or memory167allocation failure by gz_comp(), or 0 on success. */168local int gz_zero(state, len)169gz_statep state;170z_off64_t len;171{172int first;173unsigned n;174z_streamp strm = &(state->strm);175176/* consume whatever's left in the input buffer */177if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)178return -1;179180/* compress len zeros (len guaranteed > 0) */181first = 1;182while (len) {183n = GT_OFF(state->size) || (z_off64_t)state->size > len ?184(unsigned)len : state->size;185if (first) {186memset(state->in, 0, n);187first = 0;188}189strm->avail_in = n;190strm->next_in = state->in;191state->x.pos += n;192if (gz_comp(state, Z_NO_FLUSH) == -1)193return -1;194len -= n;195}196return 0;197}198199/* Write len bytes from buf to file. Return the number of bytes written. If200the returned value is less than len, then there was an error. */201local z_size_t gz_write(state, buf, len)202gz_statep state;203voidpc buf;204z_size_t len;205{206z_size_t put = len;207208/* if len is zero, avoid unnecessary operations */209if (len == 0)210return 0;211212/* allocate memory if this is the first time through */213if (state->size == 0 && gz_init(state) == -1)214return 0;215216/* check for seek request */217if (state->seek) {218state->seek = 0;219if (gz_zero(state, state->skip) == -1)220return 0;221}222223/* for small len, copy to input buffer, otherwise compress directly */224if (len < state->size) {225/* copy to input buffer, compress when full */226do {227unsigned have, copy;228229if (state->strm.avail_in == 0)230state->strm.next_in = state->in;231have = (unsigned)((state->strm.next_in + state->strm.avail_in) -232state->in);233copy = state->size - have;234if (copy > len)235copy = (unsigned)len;236memcpy(state->in + have, buf, copy);237state->strm.avail_in += copy;238state->x.pos += copy;239buf = (const char *)buf + copy;240len -= copy;241if (len && gz_comp(state, Z_NO_FLUSH) == -1)242return 0;243} while (len);244}245else {246/* consume whatever's left in the input buffer */247if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)248return 0;249250/* directly compress user buffer to file */251state->strm.next_in = (z_const Bytef *)buf;252do {253unsigned n = (unsigned)-1;254if (n > len)255n = (unsigned)len;256state->strm.avail_in = n;257state->x.pos += n;258if (gz_comp(state, Z_NO_FLUSH) == -1)259return 0;260len -= n;261} while (len);262}263264/* input was all buffered or compressed */265return put;266}267268/* -- see zlib.h -- */269int ZEXPORT gzwrite(file, buf, len)270gzFile file;271voidpc buf;272unsigned len;273{274gz_statep state;275276/* get internal structure */277if (file == NULL)278return 0;279state = (gz_statep)file;280281/* check that we're writing and that there's no error */282if (state->mode != GZ_WRITE || state->err != Z_OK)283return 0;284285/* since an int is returned, make sure len fits in one, otherwise return286with an error (this avoids a flaw in the interface) */287if ((int)len < 0) {288gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");289return 0;290}291292/* write len bytes from buf (the return value will fit in an int) */293return (int)gz_write(state, buf, len);294}295296/* -- see zlib.h -- */297z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)298voidpc buf;299z_size_t size;300z_size_t nitems;301gzFile file;302{303z_size_t len;304gz_statep state;305306/* get internal structure */307if (file == NULL)308return 0;309state = (gz_statep)file;310311/* check that we're writing and that there's no error */312if (state->mode != GZ_WRITE || state->err != Z_OK)313return 0;314315/* compute bytes to read -- error on overflow */316len = nitems * size;317if (size && len / size != nitems) {318gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");319return 0;320}321322/* write len bytes to buf, return the number of full items written */323return len ? gz_write(state, buf, len) / size : 0;324}325326/* -- see zlib.h -- */327int ZEXPORT gzputc(file, c)328gzFile file;329int c;330{331unsigned have;332unsigned char buf[1];333gz_statep state;334z_streamp strm;335336/* get internal structure */337if (file == NULL)338return -1;339state = (gz_statep)file;340strm = &(state->strm);341342/* check that we're writing and that there's no error */343if (state->mode != GZ_WRITE || state->err != Z_OK)344return -1;345346/* check for seek request */347if (state->seek) {348state->seek = 0;349if (gz_zero(state, state->skip) == -1)350return -1;351}352353/* try writing to input buffer for speed (state->size == 0 if buffer not354initialized) */355if (state->size) {356if (strm->avail_in == 0)357strm->next_in = state->in;358have = (unsigned)((strm->next_in + strm->avail_in) - state->in);359if (have < state->size) {360state->in[have] = (unsigned char)c;361strm->avail_in++;362state->x.pos++;363return c & 0xff;364}365}366367/* no room in buffer or not initialized, use gz_write() */368buf[0] = (unsigned char)c;369if (gz_write(state, buf, 1) != 1)370return -1;371return c & 0xff;372}373374/* -- see zlib.h -- */375int ZEXPORT gzputs(file, str)376gzFile file;377const char *str;378{379int ret;380z_size_t len;381gz_statep state;382383/* get internal structure */384if (file == NULL)385return -1;386state = (gz_statep)file;387388/* check that we're writing and that there's no error */389if (state->mode != GZ_WRITE || state->err != Z_OK)390return -1;391392/* write string */393len = strlen(str);394ret = (int)gz_write(state, str, len);395return ret == 0 && len != 0 ? -1 : ret;396}397398#if defined(STDC) || defined(Z_HAVE_STDARG_H)399#include <stdarg.h>400401/* -- see zlib.h -- */402int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)403{404int len;405unsigned left;406char *next;407gz_statep state;408z_streamp strm;409410/* get internal structure */411if (file == NULL)412return Z_STREAM_ERROR;413state = (gz_statep)file;414strm = &(state->strm);415416/* check that we're writing and that there's no error */417if (state->mode != GZ_WRITE || state->err != Z_OK)418return Z_STREAM_ERROR;419420/* make sure we have some buffer space */421if (state->size == 0 && gz_init(state) == -1)422return state->err;423424/* check for seek request */425if (state->seek) {426state->seek = 0;427if (gz_zero(state, state->skip) == -1)428return state->err;429}430431/* do the printf() into the input buffer, put length in len -- the input432buffer is double-sized just for this function, so there is guaranteed to433be state->size bytes available after the current contents */434if (strm->avail_in == 0)435strm->next_in = state->in;436next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);437next[state->size - 1] = 0;438#ifdef NO_vsnprintf439# ifdef HAS_vsprintf_void440(void)vsprintf(next, format, va);441for (len = 0; len < state->size; len++)442if (next[len] == 0) break;443# else444len = vsprintf(next, format, va);445# endif446#else447# ifdef HAS_vsnprintf_void448(void)vsnprintf(next, state->size, format, va);449len = strlen(next);450# else451len = vsnprintf(next, state->size, format, va);452# endif453#endif454455/* check that printf() results fit in buffer */456if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)457return 0;458459/* update buffer and position, compress first half if past that */460strm->avail_in += (unsigned)len;461state->x.pos += len;462if (strm->avail_in >= state->size) {463left = strm->avail_in - state->size;464strm->avail_in = state->size;465if (gz_comp(state, Z_NO_FLUSH) == -1)466return state->err;467memcpy(state->in, state->in + state->size, left);468strm->next_in = state->in;469strm->avail_in = left;470}471return len;472}473474int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)475{476va_list va;477int ret;478479va_start(va, format);480ret = gzvprintf(file, format, va);481va_end(va);482return ret;483}484485#else /* !STDC && !Z_HAVE_STDARG_H */486487/* -- see zlib.h -- */488int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,489a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)490gzFile file;491const char *format;492int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,493a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;494{495unsigned len, left;496char *next;497gz_statep state;498z_streamp strm;499500/* get internal structure */501if (file == NULL)502return Z_STREAM_ERROR;503state = (gz_statep)file;504strm = &(state->strm);505506/* check that can really pass pointer in ints */507if (sizeof(int) != sizeof(void *))508return Z_STREAM_ERROR;509510/* check that we're writing and that there's no error */511if (state->mode != GZ_WRITE || state->err != Z_OK)512return Z_STREAM_ERROR;513514/* make sure we have some buffer space */515if (state->size == 0 && gz_init(state) == -1)516return state->error;517518/* check for seek request */519if (state->seek) {520state->seek = 0;521if (gz_zero(state, state->skip) == -1)522return state->error;523}524525/* do the printf() into the input buffer, put length in len -- the input526buffer is double-sized just for this function, so there is guaranteed to527be state->size bytes available after the current contents */528if (strm->avail_in == 0)529strm->next_in = state->in;530next = (char *)(strm->next_in + strm->avail_in);531next[state->size - 1] = 0;532#ifdef NO_snprintf533# ifdef HAS_sprintf_void534sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,535a13, a14, a15, a16, a17, a18, a19, a20);536for (len = 0; len < size; len++)537if (next[len] == 0)538break;539# else540len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,541a12, a13, a14, a15, a16, a17, a18, a19, a20);542# endif543#else544# ifdef HAS_snprintf_void545snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,546a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);547len = strlen(next);548# else549len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,550a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);551# endif552#endif553554/* check that printf() results fit in buffer */555if (len == 0 || len >= state->size || next[state->size - 1] != 0)556return 0;557558/* update buffer and position, compress first half if past that */559strm->avail_in += len;560state->x.pos += len;561if (strm->avail_in >= state->size) {562left = strm->avail_in - state->size;563strm->avail_in = state->size;564if (gz_comp(state, Z_NO_FLUSH) == -1)565return state->err;566memcpy(state->in, state->in + state->size, left);567strm->next_in = state->in;568strm->avail_in = left;569}570return (int)len;571}572573#endif574575/* -- see zlib.h -- */576int ZEXPORT gzflush(file, flush)577gzFile file;578int flush;579{580gz_statep state;581582/* get internal structure */583if (file == NULL)584return Z_STREAM_ERROR;585state = (gz_statep)file;586587/* check that we're writing and that there's no error */588if (state->mode != GZ_WRITE || state->err != Z_OK)589return Z_STREAM_ERROR;590591/* check flush parameter */592if (flush < 0 || flush > Z_FINISH)593return Z_STREAM_ERROR;594595/* check for seek request */596if (state->seek) {597state->seek = 0;598if (gz_zero(state, state->skip) == -1)599return state->err;600}601602/* compress remaining data with requested flush */603(void)gz_comp(state, flush);604return state->err;605}606607/* -- see zlib.h -- */608int ZEXPORT gzsetparams(file, level, strategy)609gzFile file;610int level;611int strategy;612{613gz_statep state;614z_streamp strm;615616/* get internal structure */617if (file == NULL)618return Z_STREAM_ERROR;619state = (gz_statep)file;620strm = &(state->strm);621622/* check that we're writing and that there's no error */623if (state->mode != GZ_WRITE || state->err != Z_OK)624return Z_STREAM_ERROR;625626/* if no change is requested, then do nothing */627if (level == state->level && strategy == state->strategy)628return Z_OK;629630/* check for seek request */631if (state->seek) {632state->seek = 0;633if (gz_zero(state, state->skip) == -1)634return state->err;635}636637/* change compression parameters for subsequent input */638if (state->size) {639/* flush previous input with previous parameters before changing */640if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)641return state->err;642deflateParams(strm, level, strategy);643}644state->level = level;645state->strategy = strategy;646return Z_OK;647}648649/* -- see zlib.h -- */650int ZEXPORT gzclose_w(file)651gzFile file;652{653int ret = Z_OK;654gz_statep state;655656/* get internal structure */657if (file == NULL)658return Z_STREAM_ERROR;659state = (gz_statep)file;660661/* check that we're writing */662if (state->mode != GZ_WRITE)663return Z_STREAM_ERROR;664665/* check for seek request */666if (state->seek) {667state->seek = 0;668if (gz_zero(state, state->skip) == -1)669ret = state->err;670}671672/* flush, free memory, and close file */673if (gz_comp(state, Z_FINISH) == -1)674ret = state->err;675if (state->size) {676if (!state->direct) {677(void)deflateEnd(&(state->strm));678free(state->out);679}680free(state->in);681}682gz_error(state, Z_OK, NULL);683free(state->path);684if (close(state->fd) == -1)685ret = Z_ERRNO;686free(state);687return ret;688}689690691