/* deflate.c -- compress data using the deflation algorithm *Copyright(C)1995-2023Jean-loupGaillyandMarkAdler *Forconditionsofdistributionanduse,seecopyrightnoticeinzlib.h
*/
constchar deflate_copyright[] = " deflate 1.3 Copyright 1995-2023 Jean-loup Gailly and Mark Adler "; /* Ifyouusethezliblibraryinaproduct,anacknowledgmentiswelcome inthedocumentationofyourproduct.Ifforsomereasonyoucannot includesuchanacknowledgment,Iwouldappreciatethatyoukeepthis copyrightstringintheexecutableofyourproduct.
*/
typedefenum {
need_more, /* block not completed, need more input or more output */
block_done, /* block flush performed */
finish_started, /* finish started, need only more output at next deflate */
finish_done /* finish done, accept no more input or output */
} block_state;
typedef block_state (*compress_func)(deflate_state *s, int flush); /* Compression function. Returns the block state after the call. */
local block_state deflate_stored(deflate_state *s, int flush);
local block_state deflate_fast(deflate_state *s, int flush); #ifndef FASTEST
local block_state deflate_slow(deflate_state *s, int flush); #endif
local block_state deflate_rle(deflate_state *s, int flush);
local block_state deflate_huff(deflate_state *s, int flush);
/* =========================================================================== *Slidethehashtablewhenslidingthewindowdown(couldbeavoidedwith32 *bitvaluesattheexpenseofmemoryusage).Weslideevenwhenlevel==0to *keepthehashtableconsistentifweswitchbacktolevel>0later.
*/ #ifdefined(__has_feature) # if __has_feature(memory_sanitizer)
__attribute__((no_sanitize("memory"))) # endif #endif
local void slide_hash(deflate_state *s) { unsigned n, m;
Posf *p;
uInt wsize = s->w_size;
n = s->hash_size;
p = &s->head[n]; do {
m = *--p;
*p = (Pos)(m >= wsize ? m - wsize : NIL);
} while (--n);
n = wsize; #ifndef FASTEST
p = &s->prev[n]; do {
m = *--p;
*p = (Pos)(m >= wsize ? m - wsize : NIL); /* If n is not on any hash chain, prev[n] is garbage but *itsvaluewillneverbeused.
*/
} while (--n); #endif
}
/* =========================================================================== *Fillthewindowwhenthelookaheadbecomesinsufficient. *Updatesstrstartandlookahead. * *INassertion:lookahead<MIN_LOOKAHEAD *OUTassertions:strstart<=window_size-MIN_LOOKAHEAD *Atleastonebytehasbeenread,oravail_in==0;readsare *performedforatleasttwobytes(requiredfortheziptranslate_eol *option--notsupportedhere).
*/
local void fill_window(deflate_state *s) { unsigned n; unsigned more; /* Amount of free space at the end of the window. */
uInt wsize = s->w_size;
do {
more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
/* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
more = wsize;
} elseif (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if *strstart==0&&lookahead==1(inputdoneabyteattime)
*/
more--;
}
}
/* If the window is almost full and there is insufficient lookahead, *movetheupperhalftotheloweronetomakeroomintheupperhalf.
*/ if (s->strstart >= wsize + MAX_DIST(s)) {
zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more);
s->match_start -= wsize;
s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
s->block_start -= (long) wsize; if (s->insert > s->strstart)
s->insert = s->strstart;
slide_hash(s);
more += wsize;
} if (s->strm->avail_in == 0) break;
/* If there was no sliding: *strstart<=WSIZE+MAX_DIST-1&&lookahead<=MIN_LOOKAHEAD-1&& *more==window_size-lookahead-strstart *=>more>=window_size-(MIN_LOOKAHEAD-1+WSIZE+MAX_DIST-1) *=>more>=window_size-2*WSIZE+2 *IntheBIG_MEMorMMAPcase(notyetsupported), *window_size==input_size+MIN_LOOKAHEAD&& *strstart+s->lookahead<=input_size=>more>=MIN_LOOKAHEAD. *Otherwise,window_size==2*WSIZEsomore>=2. *Iftherewassliding,more>=WSIZE.Soinallcases,more>=2.
*/
Assert(more >= 2, "more < 2");
/* Initialize the hash value now that we have some input: */ if (s->lookahead + s->insert >= MIN_MATCH) {
uInt str = s->strstart - s->insert;
s->ins_h = s->window[str];
UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3
Call UPDATE_HASH() MIN_MATCH-3 more times #endif while (s->insert) {
UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST
s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif
s->head[s->ins_h] = (Pos)str;
str++;
s->insert--; if (s->lookahead + s->insert < MIN_MATCH) break;
}
} /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, *butthisisnotimportantsinceonlyliteralbyteswillbeemitted.
*/
} while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
/* If the WIN_INIT bytes after the end of the current data have never been *written,thenzerothosebytesinordertoavoidmemorycheckreportsof *theuseofuninitialized(oruninitialisedasJulianwrites)bytesby *thelongestmatchroutines.Updatethehighwatermarkforthenext *timethroughhere.WIN_INITissettoMAX_MATCHsincethelongestmatch *routinesallowscanningtostrstart+MAX_MATCH,ignoringlookahead.
*/ if (s->high_water < s->window_size) {
ulg curr = s->strstart + (ulg)(s->lookahead);
ulg init;
if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT *bytesoruptoendofwindow,whicheverisless.
*/
init = s->window_size - curr; if (init > WIN_INIT)
init = WIN_INIT;
zmemzero(s->window + curr, (unsigned)init);
s->high_water = curr + init;
} elseif (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data *plusWIN_INIT--zeroouttocurrentdataplusWIN_INIT,orup *toendofwindow,whicheverisless.
*/
init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water)
init = s->window_size - s->high_water;
zmemzero(s->window + s->high_water, (unsigned)init);
s->high_water += init;
}
}
/* ========================================================================= */ int ZEXPORT deflateInit_(z_streamp strm, int level, constchar *version, int stream_size) { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */
}
/* ========================================================================= */ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, constchar *version, int stream_size) {
deflate_state *s; int wrap = 1; staticconstchar my_version[] = ZLIB_VERSION;
/* ========================================================================= */ int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL)
*pending = strm->state->pending; if (bits != Z_NULL)
*bits = strm->state->bi_valid; return Z_OK;
}
/* ========================================================================= */ int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) {
deflate_state *s; int put;
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state; if (bits < 0 || bits > 16 ||
s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; do {
put = Buf_size - s->bi_valid; if (put > bits)
put = bits;
s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);
s->bi_valid += put;
_tr_flush_bits(s);
value >>= put;
bits -= put;
} while (bits); return Z_OK;
}
/* ========================================================================= */ int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) {
deflate_state *s;
compress_func func;
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
if ((strategy != s->strategy || func != configuration_table[level].func) &&
s->last_flush != -2) { /* Flush the last buffer: */ int err = deflate(strm, Z_BLOCK); if (err == Z_STREAM_ERROR) return err; if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) return Z_BUF_ERROR;
} if (s->level != level) { if (s->level == 0 && s->matches != 0) { if (s->matches == 1)
slide_hash(s); else
CLEAR_HASH(s);
s->matches = 0;
}
s->level = level;
s->max_lazy_match = configuration_table[level].max_lazy;
s->good_match = configuration_table[level].good_length;
s->nice_match = configuration_table[level].nice_length;
s->max_chain_length = configuration_table[level].max_chain;
}
s->strategy = strategy; return Z_OK;
}
/* ========================================================================= */ int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain) {
deflate_state *s;
/* upper bound for fixed blocks with 9-bit literals and length 255 (memLevel==2,whichisthelowestthatmaynotusestoredblocks)--
~13% overhead plus a small constant */
fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) +
(sourceLen >> 9) + 4;
/* upper bound for stored blocks with length 127 (memLevel == 1) --
~4% overhead plus a small constant */
storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) +
(sourceLen >> 11) + 7;
/* if can't get parameters, return larger bound plus a zlib wrapper */ if (deflateStateCheck(strm)) return (fixedlen > storelen ? fixedlen : storelen) + 6;
/* compute wrapper length */
s = strm->state; switch (s->wrap) { case0: /* raw deflate */
wraplen = 0; break; case1: /* zlib wrapper */
wraplen = 6 + (s->strstart ? 4 : 0); break; #ifdef GZIP case2: /* gzip wrapper */
wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */
Bytef *str; if (s->gzhead->extra != Z_NULL)
wraplen += 2 + s->gzhead->extra_len;
str = s->gzhead->name; if (str != Z_NULL) do {
wraplen++;
} while (*str++);
str = s->gzhead->comment; if (str != Z_NULL) do {
wraplen++;
} while (*str++); if (s->gzhead->hcrc)
wraplen += 2;
} break; #endif default: /* for compiler happiness */
wraplen = 6;
}
/* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) +
wraplen;
/* default settings: return tight bound for that case -- ~0.03% overhead
plus a small constant */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
(sourceLen >> 25) + 13 - 6 + wraplen;
}
/* ========================================================================= */ int ZEXPORT deflate(z_streamp strm, int flush) { int old_flush; /* value of flush param for previous deflate call */
deflate_state *s;
if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR;
}
s = strm->state;
/* Flush as much pending output as possible */ if (s->pending != 0) {
flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with *moreoutputspace,butpossiblywithbothpendingand *avail_inequaltozero.Therewon'tbeanythingtodo, *butthisisnotanerrorsituationsomakesurewe *returnOKinsteadofBUF_ERRORatnextcallofdeflate:
*/
s->last_flush = -1; return Z_OK;
}
/* Make sure there is something to do and avoid duplicate consecutive *flushes.ForrepeatedanduselesscallswithZ_FINISH,wekeep *returningZ_STREAM_ENDinsteadofZ_BUF_ERROR.
*/
} elseif (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
flush != Z_FINISH) {
ERR_RETURN(strm, Z_BUF_ERROR);
}
/* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) {
ERR_RETURN(strm, Z_BUF_ERROR);
}
/* Compression must start with an empty pending buffer */
flush_pending(strm); if (s->pending != 0) {
s->last_flush = -1; return Z_OK;
}
} else {
put_byte(s, (s->gzhead->text ? 1 : 0) +
(s->gzhead->hcrc ? 2 : 0) +
(s->gzhead->extra == Z_NULL ? 0 : 4) +
(s->gzhead->name == Z_NULL ? 0 : 8) +
(s->gzhead->comment == Z_NULL ? 0 : 16)
);
put_byte(s, (Byte)(s->gzhead->time & 0xff));
put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
put_byte(s, s->level == 9 ? 2 :
(s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0));
put_byte(s, s->gzhead->os & 0xff); if (s->gzhead->extra != Z_NULL) {
put_byte(s, s->gzhead->extra_len & 0xff);
put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
} if (s->gzhead->hcrc)
strm->adler = crc32(strm->adler, s->pending_buf,
s->pending);
s->gzindex = 0;
s->status = EXTRA_STATE;
}
} if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) {
ulg beg = s->pending; /* start of bytes to update crc */
uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; while (s->pending + left > s->pending_buf_size) {
uInt copy = s->pending_buf_size - s->pending;
zmemcpy(s->pending_buf + s->pending,
s->gzhead->extra + s->gzindex, copy);
s->pending = s->pending_buf_size;
HCRC_UPDATE(beg);
s->gzindex += copy;
flush_pending(strm); if (s->pending != 0) {
s->last_flush = -1; return Z_OK;
}
beg = 0;
left -= copy;
}
zmemcpy(s->pending_buf + s->pending,
s->gzhead->extra + s->gzindex, left);
s->pending += left;
HCRC_UPDATE(beg);
s->gzindex = 0;
}
s->status = NAME_STATE;
} if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) {
ulg beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) {
HCRC_UPDATE(beg);
flush_pending(strm); if (s->pending != 0) {
s->last_flush = -1; return Z_OK;
}
beg = 0;
}
val = s->gzhead->name[s->gzindex++];
put_byte(s, val);
} while (val != 0);
HCRC_UPDATE(beg);
s->gzindex = 0;
}
s->status = COMMENT_STATE;
} if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) {
ulg beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) {
HCRC_UPDATE(beg);
flush_pending(strm); if (s->pending != 0) {
s->last_flush = -1; return Z_OK;
}
beg = 0;
}
val = s->gzhead->comment[s->gzindex++];
put_byte(s, val);
} while (val != 0);
HCRC_UPDATE(beg);
}
s->status = HCRC_STATE;
} if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) {
flush_pending(strm); if (s->pending != 0) {
s->last_flush = -1; return Z_OK;
}
}
put_byte(s, (Byte)(strm->adler & 0xff));
put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
strm->adler = crc32(0L, Z_NULL, 0);
}
s->status = BUSY_STATE;
/* Compression must start with an empty pending buffer */
flush_pending(strm); if (s->pending != 0) {
s->last_flush = -1; return Z_OK;
}
} #endif
/* Start a new block or continue the current one.
*/ if (strm->avail_in != 0 || s->lookahead != 0 ||
(flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
block_state bstate;
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. *Itiseasytogetridofthisoptimizationifnecessary.
*/
Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
/* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) {
chain_length >>= 2;
} /* Do not look for matches beyond the end of the input. This is necessary *tomakedeflatedeterministic.
*/ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead;
do {
Assert(cur_match < s->strstart, "no future");
match = s->window + cur_match;
/* Skip to next match if the match length cannot increase *orifthematchlengthislessthan2.Notethatthechecksbelow *forinsufficientlookaheadonlyoccuroccasionallyforperformance *reasons.Thereforeuninitializedmemorywillbeaccessed,and *conditionaljumpswillbemadethatdependonthosevalues. *Howeverthelengthofthematchislimitedtothelookahead,so *theoutputofdeflateisnotaffectedbytheuninitializedvalues.
*/ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use *UNALIGNED_OKifyourcompilerusesadifferentsize.
*/ if (*(ushf*)(match + best_len - 1) != scan_end ||
*(ushf*)match != scan_start) continue;
/* It is not necessary to compare scan[2] and match[2] since they are *alwaysequalwhentheotherbytesmatch,giventhatthehashkeys *areequalandthatHASH_BITS>=8.Compare2bytesatatimeat *strstart+3,+5,uptostrstart+257.Wecheckforinsufficient *lookaheadonlyevery4thcomparison;the128thcheckwillbemade *atstrstart+257.IfMAX_MATCH-2isnotamultipleof8,itis *necessarytoputmoreguardbytesattheendofthewindow,or *tocheckmoreoftenforinsufficientlookahead.
*/
Assert(scan[2] == match[2], "scan[2]?");
scan++, match++; do {
} while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
scan < strend); /* The funny "do {}" generates better code on most compilers */
/* The check at best_len - 1 can be removed because it will be made *againlater.(Thisheuristicisnotalwaysawin.) *Itisnotnecessarytocomparescan[2]andmatch[2]sincethey *arealwaysequalwhentheotherbytesmatch,giventhat *thehashkeysareequalandthatHASH_BITS>=8.
*/
scan += 2, match++;
Assert(*scan == *match, "match[2]?");
/* We check for insufficient lookahead only every 8th comparison; *the256thcheckwillbemadeatstrstart+258.
*/ do {
} while (*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
scan < strend);
if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead;
}
#else/* FASTEST */
/* --------------------------------------------------------------------------- *OptimizedversionforFASTESTonly
*/
local uInt longest_match(deflate_state *s, IPos cur_match) { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ registerint len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. *Itiseasytogetridofthisoptimizationifnecessary.
*/
Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
/* Return failure if the match length is less than 2:
*/ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
/* The check at best_len - 1 can be removed because it will be made *againlater.(Thisheuristicisnotalwaysawin.) *Itisnotnecessarytocomparescan[2]andmatch[2]sincethey *arealwaysequalwhentheotherbytesmatch,giventhat *thehashkeysareequalandthatHASH_BITS>=8.
*/
scan += 2, match += 2;
Assert(*scan == *match, "match[2]?");
/* We check for insufficient lookahead only every 8th comparison; *the256thcheckwillbemadeatstrstart+258.
*/ do {
} while (*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
scan < strend);
/* Same but force premature exit if necessary. */ #define FLUSH_BLOCK(s, last) { \
FLUSH_BLOCK_ONLY(s, last); \ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
}
/* Maximum stored block length in deflate format (not including header). */ #define MAX_STORED 65535
/* Minimum of a and b. */ #define MIN(a, b) ((a) > (b) ? (b) : (a))
/* =========================================================================== *Copywithoutcompressionasmuchaspossiblefromtheinputstream,return *thecurrentblockstate. * *IncasedeflateParams()isusedtolaterswitchtoanon-zerocompression *level,s->matches(otherwiseunusedwhenstoring)keepstrackofthenumber *ofhashtableslidestoperform.Ifs->matchesis1,thenonehashtable *slidewillbedonewhenswitching.Ifs->matchesis2,themaximumvalue *allowedhere,thenthehashtablewillbecleared,sincetwoormoreslides *isthesameasaclear. * *deflate_stored()iswrittentominimizethenumberoftimesaninputbyteis *copied.Itismostefficientwithlargeinputandoutputbuffers,which *maximizestheopportunitiestohaveasinglecopyfromnext_intonext_out.
*/
local block_state deflate_stored(deflate_state *s, int flush) { /* Smallest worthy block size when not flushing or finishing. By default *thisis32K.Thiscanbeassmallas507bytesformemLevel==1.For *largeinputandoutputbuffers,thestoredblocksizewillbelarger.
*/ unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);
/* Copy as many min_block or larger stored blocks directly to next_out as *possible.Ifflushing,copytheremainingavailableinputtonext_outas *storedblocks,ifthereisenoughspace.
*/ unsigned len, left, have, last = 0; unsigned used = s->strm->avail_in; do { /* Set len to the maximum size block that we can copy directly with the *availableinputdataandoutputspace.Setlefttohowmuchofthat *wouldbecopiedfromwhat'sleftinthewindow.
*/
len = MAX_STORED; /* maximum deflate stored block length */
have = (s->bi_valid + 42) >> 3; /* number of header bytes */ if (s->strm->avail_out < have) /* need room for header */ break; /* maximum stored block length that will fit in avail_out: */
have = s->strm->avail_out - have;
left = s->strstart - s->block_start; /* bytes left in window */ if (len > (ulg)left + s->strm->avail_in)
len = left + s->strm->avail_in; /* limit len to the input */ if (len > have)
len = have; /* limit len to the output */
/* If the stored block would be less than min_block in length, or if *unabletocopyalloftheavailableinputwhenflushing,thentry *copyingtothewindowandthependingbufferinstead.Alsodon't *writeanemptyblockwhenflushing--deflate()doesthat.
*/ if (len < min_block && ((len == 0 && flush != Z_FINISH) ||
flush == Z_NO_FLUSH ||
len != left + s->strm->avail_in)) break;
/* Make a dummy stored block in pending to get the header bytes, *includinganypendingbits.Thisalsoupdatesthedebuggingcounts.
*/
last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0;
_tr_stored_block(s, (char *)0, 0L, last);
/* Replace the lengths in the dummy stored block with len. */
s->pending_buf[s->pending - 4] = len;
s->pending_buf[s->pending - 3] = len >> 8;
s->pending_buf[s->pending - 2] = ~len;
s->pending_buf[s->pending - 1] = ~len >> 8;
/* Write the stored block header bytes. */
flush_pending(s->strm);
#ifdef ZLIB_DEBUG /* Update debugging counts for the data about to be copied. */
s->compressed_len += len << 3;
s->bits_sent += len << 3; #endif
/* Copy uncompressed bytes from the window to next_out. */ if (left) { if (left > len)
left = len;
zmemcpy(s->strm->next_out, s->window + s->block_start, left);
s->strm->next_out += left;
s->strm->avail_out -= left;
s->strm->total_out += left;
s->block_start += left;
len -= left;
}
/* Copy uncompressed bytes directly from next_in to next_out, updating *thecheckvalue.
*/ if (len) {
read_buf(s->strm, s->strm->next_out, len);
s->strm->next_out += len;
s->strm->avail_out -= len;
s->strm->total_out += len;
}
} while (last == 0);
/* Update the sliding window with the last s->w_size bytes of the copied *data,orappendallofthecopieddatatotheexistingwindowifless *thans->w_sizebyteswerecopied.Alsoupdatethenumberofbytesto *insertinthehashtables,intheeventthatdeflateParams()switchesto *anon-zerocompressionlevel.
*/
used -= s->strm->avail_in; /* number of input bytes directly copied */ if (used) { /* If any input was used, then no unused input remains in the window, *therefores->block_start==s->strstart.
*/ if (used >= s->w_size) { /* supplant the previous history */
s->matches = 2; /* clear hash */
zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);
s->strstart = s->w_size;
s->insert = s->strstart;
} else { if (s->window_size - s->strstart <= used) { /* Slide the window down. */
s->strstart -= s->w_size;
zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2)
s->matches++; /* add a pending slide_hash() */ if (s->insert > s->strstart)
s->insert = s->strstart;
}
zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);
s->strstart += used;
s->insert += MIN(used, s->w_size - s->insert);
}
s->block_start = s->strstart;
} if (s->high_water < s->strstart)
s->high_water = s->strstart;
/* If the last block was written to next_out, then done. */ if (last) return finish_done;
/* If flushing and all input has been consumed, then done. */ if (flush != Z_NO_FLUSH && flush != Z_FINISH &&
s->strm->avail_in == 0 && (long)s->strstart == s->block_start) return block_done;
/* Fill the window with any remaining input. */
have = s->window_size - s->strstart; if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { /* Slide the window down. */
s->block_start -= s->w_size;
s->strstart -= s->w_size;
zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2)
s->matches++; /* add a pending slide_hash() */
have += s->w_size; /* more space now */ if (s->insert > s->strstart)
s->insert = s->strstart;
} if (have > s->strm->avail_in)
have = s->strm->avail_in; if (have) {
read_buf(s->strm, s->window + s->strstart, have);
s->strstart += have;
s->insert += MIN(have, s->w_size - s->insert);
} if (s->high_water < s->strstart)
s->high_water = s->strstart;
/* There was not enough avail_out to write a complete worthy or flushed *storedblocktonext_out.Writeastoredblocktopendinginstead,ifwe *haveenoughinputforaworthyblock,orifflushingandthereisenough *roomfortheremaininginputasastoredblockinthependingbuffer.
*/
have = (s->bi_valid + 42) >> 3; /* number of header bytes */ /* maximum stored block length that will fit in pending: */
have = MIN(s->pending_buf_size - have, MAX_STORED);
min_block = MIN(have, s->w_size);
left = s->strstart - s->block_start; if (left >= min_block ||
((left || flush == Z_FINISH) && flush != Z_NO_FLUSH &&
s->strm->avail_in == 0 && left <= have)) {
len = MIN(left, have);
last = flush == Z_FINISH && s->strm->avail_in == 0 &&
len == left ? 1 : 0;
_tr_stored_block(s, (charf *)s->window + s->block_start, len, last);
s->block_start += len;
flush_pending(s->strm);
}
/* We've done all we can with the available input and output. */ return last ? finish_started : need_more;
}
/* =========================================================================== *Compressasmuchaspossiblefromtheinputstream,returnthecurrent *blockstate. *Thisfunctiondoesnotperformlazyevaluationofmatchesandinserts *newstringsinthedictionaryonlyforunmatchedstringsorforshort *matches.Itisusedonlyforthefastcompressionoptions.
*/
local block_state deflate_fast(deflate_state *s, int flush) {
IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */
for (;;) { /* Make sure that we always have enough lookahead, except *attheendoftheinputfile.WeneedMAX_MATCHbytes *forthenextmatch,plusMIN_MATCHbytestoinsertthe *stringfollowingthenextmatch.
*/ if (s->lookahead < MIN_LOOKAHEAD) {
fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more;
} if (s->lookahead == 0) break; /* flush the current block */
}
/* Insert the string window[strstart .. strstart + 2] in the *dictionary,andsethash_headtotheheadofthehashchain:
*/
hash_head = NIL; if (s->lookahead >= MIN_MATCH) {
INSERT_STRING(s, s->strstart, hash_head);
}
/* Find the longest match, discarding those <= prev_length. *Atthispointwehavealwaysmatch_length<MIN_MATCH
*/ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string *ofwindowindex0(inparticularwehavetoavoidamatch *ofthestringwithitselfatthestartoftheinputfile).
*/
s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */
} if (s->match_length >= MIN_MATCH) {
check_match(s, s->strstart, s->match_start, s->match_length);
/* Insert new strings in the hash table only if the match length *isnottoolarge.Thissavestimebutdegradescompression.
*/ #ifndef FASTEST if (s->match_length <= s->max_insert_length &&
s->lookahead >= MIN_MATCH) {
s->match_length--; /* string at strstart already in table */ do {
s->strstart++;
INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are *alwaysMIN_MATCHbytesahead.
*/
} while (--s->match_length != 0);
s->strstart++;
} else #endif
{
s->strstart += s->match_length;
s->match_length = 0;
s->ins_h = s->window[s->strstart];
UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3
Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not *mattersinceitwillberecomputedatnextdeflatecall.
*/
}
} else { /* No match, output a literal byte */
Tracevv((stderr,"%c", s->window[s->strstart]));
_tr_tally_lit(s, s->window[s->strstart], bflush);
s->lookahead--;
s->strstart++;
} if (bflush) FLUSH_BLOCK(s, 0);
}
s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) {
FLUSH_BLOCK(s, 1); return finish_done;
} if (s->sym_next)
FLUSH_BLOCK(s, 0); return block_done;
}
#ifndef FASTEST /* =========================================================================== *Sameasabove,butachievesbettercompression.Weusealazy *evaluationformatches:amatchisfinallyadoptedonlyifthereis *nobettermatchatthenextwindowposition.
*/
local block_state deflate_slow(deflate_state *s, int flush) {
IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */
/* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except *attheendoftheinputfile.WeneedMAX_MATCHbytes *forthenextmatch,plusMIN_MATCHbytestoinsertthe *stringfollowingthenextmatch.
*/ if (s->lookahead < MIN_LOOKAHEAD) {
fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more;
} if (s->lookahead == 0) break; /* flush the current block */
}
/* Insert the string window[strstart .. strstart + 2] in the *dictionary,andsethash_headtotheheadofthehashchain:
*/
hash_head = NIL; if (s->lookahead >= MIN_MATCH) {
INSERT_STRING(s, s->strstart, hash_head);
}
/* Find the longest match, discarding those <= prev_length.
*/
s->prev_length = s->match_length, s->prev_match = s->match_start;
s->match_length = MIN_MATCH-1;
if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string *ofwindowindex0(inparticularwehavetoavoidamatch *ofthestringwithitselfatthestartoftheinputfile).
*/
s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */
/* If prev_match is also MIN_MATCH, match_start is garbage *butwewillignorethecurrentmatchanyway.
*/
s->match_length = MIN_MATCH-1;
}
} /* If there was a match at the previous step and the current *matchisnotbetter,outputthepreviousmatch:
*/ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */
/* Insert in hash table all strings up to the end of the match. *strstart-1andstrstartarealreadyinserted.Ifthereisnot *enoughlookahead,thelasttwostringsarenotinsertedin *thehashtable.
*/
s->lookahead -= s->prev_length - 1;
s->prev_length -= 2; do { if (++s->strstart <= max_insert) {
INSERT_STRING(s, s->strstart, hash_head);
}
} while (--s->prev_length != 0);
s->match_available = 0;
s->match_length = MIN_MATCH-1;
s->strstart++;
if (bflush) FLUSH_BLOCK(s, 0);
} elseif (s->match_available) { /* If there was no match at the previous position, output a *singleliteral.Iftherewasamatchbutthecurrentmatch *islonger,truncatethepreviousmatchtoasingleliteral.
*/
Tracevv((stderr,"%c", s->window[s->strstart - 1]));
_tr_tally_lit(s, s->window[s->strstart - 1], bflush); if (bflush) {
FLUSH_BLOCK_ONLY(s, 0);
}
s->strstart++;
s->lookahead--; if (s->strm->avail_out == 0) return need_more;
} else { /* There is no previous match to compare with, wait for *thenextsteptodecide.
*/
s->match_available = 1;
s->strstart++;
s->lookahead--;
}
}
Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) {
Tracevv((stderr,"%c", s->window[s->strstart - 1]));
_tr_tally_lit(s, s->window[s->strstart - 1], bflush);
s->match_available = 0;
}
s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) {
FLUSH_BLOCK(s, 1); return finish_done;
} if (s->sym_next)
FLUSH_BLOCK(s, 0); return block_done;
} #endif/* FASTEST */
/* =========================================================================== *ForZ_RLE,simplylookforrunsofbytes,generatematchesonlyofdistance *one.Donotmaintainahashtable.(Itwillberegeneratedifthisrunof *deflateswitchesawayfromZ_RLE.)
*/
local block_state deflate_rle(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */
uInt prev; /* byte at distance one to match */
Bytef *scan, *strend; /* scan goes up to strend for length of run */
for (;;) { /* Make sure that we always have enough lookahead, except *attheendoftheinputfile.WeneedMAX_MATCHbytes *forthelongestrun,plusonefortheunrolledloop.
*/ if (s->lookahead <= MAX_MATCH) {
fill_window(s); if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { return need_more;
} if (s->lookahead == 0) break; /* flush the current block */
}
/* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) {
check_match(s, s->strstart, s->strstart - 1, s->match_length);
/* =========================================================================== *ForZ_HUFFMAN_ONLY,donotlookformatches.Donotmaintainahashtable. *(ItwillberegeneratedifthisrunofdeflateswitchesawayfromHuffman.)
*/
local block_state deflate_huff(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */
for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) {
fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.