|
|
@ -52,7 +52,7 @@ |
|
|
|
#include "deflate.h" |
|
|
|
#include "deflate.h" |
|
|
|
|
|
|
|
|
|
|
|
const char deflate_copyright[] = |
|
|
|
const char deflate_copyright[] = |
|
|
|
" deflate 1.0.9 Copyright 1995-1998 Jean-loup Gailly "; |
|
|
|
" deflate 1.1.0 Copyright 1995-1998 Jean-loup Gailly "; |
|
|
|
/*
|
|
|
|
/*
|
|
|
|
If you use the zlib library in a product, an acknowledgment is welcome |
|
|
|
If you use the zlib library in a product, an acknowledgment is welcome |
|
|
|
in the documentation of your product. If for some reason you cannot |
|
|
|
in the documentation of your product. If for some reason you cannot |
|
|
@ -160,14 +160,23 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ |
|
|
|
* Insert string str in the dictionary and set match_head to the previous head |
|
|
|
* Insert string str in the dictionary and set match_head to the previous head |
|
|
|
* of the hash chain (the most recent string with same hash key). Return |
|
|
|
* of the hash chain (the most recent string with same hash key). Return |
|
|
|
* the previous length of the hash chain. |
|
|
|
* the previous length of the hash chain. |
|
|
|
|
|
|
|
* If this file is compiled with -DFASTEST, the compression level is forced |
|
|
|
|
|
|
|
* to 1, and no hash chains are maintained. |
|
|
|
* IN assertion: all calls to to INSERT_STRING are made with consecutive |
|
|
|
* IN assertion: all calls to to INSERT_STRING are made with consecutive |
|
|
|
* input characters and the first MIN_MATCH bytes of str are valid |
|
|
|
* input characters and the first MIN_MATCH bytes of str are valid |
|
|
|
* (except for the last MIN_MATCH-1 bytes of the input file). |
|
|
|
* (except for the last MIN_MATCH-1 bytes of the input file). |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
#ifdef FASTEST |
|
|
|
|
|
|
|
#define INSERT_STRING(s, str, match_head) \ |
|
|
|
|
|
|
|
(UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
|
|
|
|
|
|
|
|
match_head = s->head[s->ins_h], \
|
|
|
|
|
|
|
|
s->head[s->ins_h] = (Pos)(str)) |
|
|
|
|
|
|
|
#else |
|
|
|
#define INSERT_STRING(s, str, match_head) \ |
|
|
|
#define INSERT_STRING(s, str, match_head) \ |
|
|
|
(UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
|
|
|
|
(UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
|
|
|
|
s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
|
|
|
|
s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
|
|
|
|
s->head[s->ins_h] = (Pos)(str)) |
|
|
|
s->head[s->ins_h] = (Pos)(str)) |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* ===========================================================================
|
|
|
|
/* ===========================================================================
|
|
|
|
* Initialize the hash table (avoiding 64K overflow for 16 bit systems). |
|
|
|
* Initialize the hash table (avoiding 64K overflow for 16 bit systems). |
|
|
@ -224,6 +233,9 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, |
|
|
|
if (strm->zfree == Z_NULL) strm->zfree = zcfree; |
|
|
|
if (strm->zfree == Z_NULL) strm->zfree = zcfree; |
|
|
|
|
|
|
|
|
|
|
|
if (level == Z_DEFAULT_COMPRESSION) level = 6; |
|
|
|
if (level == Z_DEFAULT_COMPRESSION) level = 6; |
|
|
|
|
|
|
|
#ifdef FASTEST |
|
|
|
|
|
|
|
level = 1; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
if (windowBits < 0) { /* undocumented feature: suppress zlib header */ |
|
|
|
if (windowBits < 0) { /* undocumented feature: suppress zlib header */ |
|
|
|
noheader = 1; |
|
|
|
noheader = 1; |
|
|
@ -708,6 +720,7 @@ local void lm_init (s) |
|
|
|
/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
|
|
|
|
/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
|
|
|
|
* match.S. The code will be functionally equivalent. |
|
|
|
* match.S. The code will be functionally equivalent. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
#ifndef FASTEST |
|
|
|
local uInt longest_match(s, cur_match) |
|
|
|
local uInt longest_match(s, cur_match) |
|
|
|
deflate_state *s; |
|
|
|
deflate_state *s; |
|
|
|
IPos cur_match; /* current match */ |
|
|
|
IPos cur_match; /* current match */ |
|
|
@ -845,6 +858,64 @@ local uInt longest_match(s, cur_match) |
|
|
|
if ((uInt)best_len <= s->lookahead) return (uInt)best_len; |
|
|
|
if ((uInt)best_len <= s->lookahead) return (uInt)best_len; |
|
|
|
return s->lookahead; |
|
|
|
return s->lookahead; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#else /* FASTEST */ |
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
* Optimized version for level == 1 only |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
local uInt longest_match(s, cur_match) |
|
|
|
|
|
|
|
deflate_state *s; |
|
|
|
|
|
|
|
IPos cur_match; /* current match */ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
register Bytef *scan = s->window + s->strstart; /* current string */ |
|
|
|
|
|
|
|
register Bytef *match; /* matched string */ |
|
|
|
|
|
|
|
register int 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.
|
|
|
|
|
|
|
|
* It is easy to get rid of this optimization if necessary. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert(cur_match < s->strstart, "no future"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match = s->window + cur_match; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
|
|
|
* again later. (This heuristic is not always a win.) |
|
|
|
|
|
|
|
* It is not necessary to compare scan[2] and match[2] since they |
|
|
|
|
|
|
|
* are always equal when the other bytes match, given that |
|
|
|
|
|
|
|
* the hash keys are equal and that HASH_BITS >= 8. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
scan += 2, match += 2; |
|
|
|
|
|
|
|
Assert(*scan == *match, "match[2]?"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* We check for insufficient lookahead only every 8th comparison;
|
|
|
|
|
|
|
|
* the 256th check will be made at strstart+258. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
do { |
|
|
|
|
|
|
|
} while (*++scan == *++match && *++scan == *++match && |
|
|
|
|
|
|
|
*++scan == *++match && *++scan == *++match && |
|
|
|
|
|
|
|
*++scan == *++match && *++scan == *++match && |
|
|
|
|
|
|
|
*++scan == *++match && *++scan == *++match && |
|
|
|
|
|
|
|
scan < strend); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
len = MAX_MATCH - (int)(strend - scan); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (len < MIN_MATCH) return MIN_MATCH - 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s->match_start = cur_match; |
|
|
|
|
|
|
|
return len <= s->lookahead ? len : s->lookahead; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif /* FASTEST */ |
|
|
|
#endif /* ASMV */ |
|
|
|
#endif /* ASMV */ |
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
#ifdef DEBUG |
|
|
@ -930,6 +1001,7 @@ local void fill_window(s) |
|
|
|
} while (--n); |
|
|
|
} while (--n); |
|
|
|
|
|
|
|
|
|
|
|
n = wsize; |
|
|
|
n = wsize; |
|
|
|
|
|
|
|
#ifndef FASTEST |
|
|
|
p = &s->prev[n]; |
|
|
|
p = &s->prev[n]; |
|
|
|
do { |
|
|
|
do { |
|
|
|
m = *--p; |
|
|
|
m = *--p; |
|
|
@ -938,6 +1010,7 @@ local void fill_window(s) |
|
|
|
* its value will never be used. |
|
|
|
* its value will never be used. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
} while (--n); |
|
|
|
} while (--n); |
|
|
|
|
|
|
|
#endif |
|
|
|
more += wsize; |
|
|
|
more += wsize; |
|
|
|
} |
|
|
|
} |
|
|
|
if (s->strm->avail_in == 0) return; |
|
|
|
if (s->strm->avail_in == 0) return; |
|
|
@ -1105,14 +1178,15 @@ local block_state deflate_fast(s, flush) |
|
|
|
if (s->match_length >= MIN_MATCH) { |
|
|
|
if (s->match_length >= MIN_MATCH) { |
|
|
|
check_match(s, s->strstart, s->match_start, s->match_length); |
|
|
|
check_match(s, s->strstart, s->match_start, s->match_length); |
|
|
|
|
|
|
|
|
|
|
|
bflush = _tr_tally(s, s->strstart - s->match_start, |
|
|
|
_tr_tally_dist(s, s->strstart - s->match_start, |
|
|
|
s->match_length - MIN_MATCH); |
|
|
|
s->match_length - MIN_MATCH, bflush); |
|
|
|
|
|
|
|
|
|
|
|
s->lookahead -= s->match_length; |
|
|
|
s->lookahead -= s->match_length; |
|
|
|
|
|
|
|
|
|
|
|
/* Insert new strings in the hash table only if the match length
|
|
|
|
/* Insert new strings in the hash table only if the match length
|
|
|
|
* is not too large. This saves time but degrades compression. |
|
|
|
* is not too large. This saves time but degrades compression. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
#ifndef FASTEST |
|
|
|
if (s->match_length <= s->max_insert_length && |
|
|
|
if (s->match_length <= s->max_insert_length && |
|
|
|
s->lookahead >= MIN_MATCH) { |
|
|
|
s->lookahead >= MIN_MATCH) { |
|
|
|
s->match_length--; /* string at strstart already in hash table */ |
|
|
|
s->match_length--; /* string at strstart already in hash table */ |
|
|
@ -1124,7 +1198,9 @@ local block_state deflate_fast(s, flush) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
} while (--s->match_length != 0); |
|
|
|
} while (--s->match_length != 0); |
|
|
|
s->strstart++;
|
|
|
|
s->strstart++;
|
|
|
|
} else { |
|
|
|
} else |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
{ |
|
|
|
s->strstart += s->match_length; |
|
|
|
s->strstart += s->match_length; |
|
|
|
s->match_length = 0; |
|
|
|
s->match_length = 0; |
|
|
|
s->ins_h = s->window[s->strstart]; |
|
|
|
s->ins_h = s->window[s->strstart]; |
|
|
@ -1139,7 +1215,7 @@ local block_state deflate_fast(s, flush) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
/* No match, output a literal byte */ |
|
|
|
/* No match, output a literal byte */ |
|
|
|
Tracevv((stderr,"%c", s->window[s->strstart])); |
|
|
|
Tracevv((stderr,"%c", s->window[s->strstart])); |
|
|
|
bflush = _tr_tally (s, 0, s->window[s->strstart]); |
|
|
|
_tr_tally_lit (s, s->window[s->strstart], bflush); |
|
|
|
s->lookahead--; |
|
|
|
s->lookahead--; |
|
|
|
s->strstart++;
|
|
|
|
s->strstart++;
|
|
|
|
} |
|
|
|
} |
|
|
@ -1245,7 +1321,8 @@ local block_state deflate_slow(s, flush) |
|
|
|
* is longer, truncate the previous match to a single literal. |
|
|
|
* is longer, truncate the previous match to a single literal. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
Tracevv((stderr,"%c", s->window[s->strstart-1])); |
|
|
|
Tracevv((stderr,"%c", s->window[s->strstart-1])); |
|
|
|
if (_tr_tally (s, 0, s->window[s->strstart-1])) { |
|
|
|
_tr_tally_lit(s, s->window[s->strstart-1], bflush); |
|
|
|
|
|
|
|
if (bflush) { |
|
|
|
FLUSH_BLOCK_ONLY(s, 0); |
|
|
|
FLUSH_BLOCK_ONLY(s, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
s->strstart++; |
|
|
|
s->strstart++; |
|
|
@ -1263,7 +1340,7 @@ local block_state deflate_slow(s, flush) |
|
|
|
Assert (flush != Z_NO_FLUSH, "no flush?"); |
|
|
|
Assert (flush != Z_NO_FLUSH, "no flush?"); |
|
|
|
if (s->match_available) { |
|
|
|
if (s->match_available) { |
|
|
|
Tracevv((stderr,"%c", s->window[s->strstart-1])); |
|
|
|
Tracevv((stderr,"%c", s->window[s->strstart-1])); |
|
|
|
_tr_tally (s, 0, s->window[s->strstart-1]); |
|
|
|
_tr_tally_lit(s, s->window[s->strstart-1], bflush); |
|
|
|
s->match_available = 0; |
|
|
|
s->match_available = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
FLUSH_BLOCK(s, flush == Z_FINISH); |
|
|
|
FLUSH_BLOCK(s, flush == Z_FINISH); |
|
|
|