📄 zdeflate.pas
字号:
dest^.state := pInternal_state(ds);
ds^ := ss^;
ds^.strm := dest;
ds^.window := pzByteArray ( ZALLOC(dest^, ds^.w_size, 2*sizeof(Byte)) );
ds^.prev := pzPosfArray ( ZALLOC(dest^, ds^.w_size, sizeof(Pos)) );
ds^.head := pzPosfArray ( ZALLOC(dest^, ds^.hash_size, sizeof(Pos)) );
overlay := pushfArray ( ZALLOC(dest^, ds^.lit_bufsize, sizeof(ush)+2) );
ds^.pending_buf := pzByteArray ( overlay );
if (ds^.window = Z_NULL) or (ds^.prev = Z_NULL) or (ds^.head = Z_NULL)
or (ds^.pending_buf = Z_NULL) then
begin
deflateEnd (dest^);
deflateCopy := Z_MEM_ERROR;
exit;
end;
{ following zmemcpy do not work for 16-bit MSDOS }
zmemcpy(pBytef(ds^.window), pBytef(ss^.window), ds^.w_size * 2 * sizeof(Byte));
zmemcpy(pBytef(ds^.prev), pBytef(ss^.prev), ds^.w_size * sizeof(Pos));
zmemcpy(pBytef(ds^.head), pBytef(ss^.head), ds^.hash_size * sizeof(Pos));
zmemcpy(pBytef(ds^.pending_buf), pBytef(ss^.pending_buf), uInt(ds^.pending_buf_size));
ds^.pending_out := @ds^.pending_buf^[ptr2int(ss^.pending_out) - ptr2int(ss^.pending_buf)];
ds^.d_buf := pushfArray (@overlay^[ds^.lit_bufsize div sizeof(ush)] );
ds^.l_buf := puchfArray (@ds^.pending_buf^[(1+sizeof(ush))*ds^.lit_bufsize]);
ds^.l_desc.dyn_tree := tree_ptr(@ds^.dyn_ltree);
ds^.d_desc.dyn_tree := tree_ptr(@ds^.dyn_dtree);
ds^.bl_desc.dyn_tree := tree_ptr(@ds^.bl_tree);
deflateCopy := Z_OK;
{$endif}
end;
{ ===========================================================================
Read a new buffer from the current input stream, update the adler32
and total number of bytes read. All deflate() input goes through
this function so some applications may wish to modify it to avoid
allocating a large strm^.next_in buffer and copying from it.
(See also flush_pending()). }
{local}
function read_buf(strm : z_streamp; buf : pBytef; size : unsigned) : int;
var
len : unsigned;
begin
len := strm^.avail_in;
if (len > size) then
len := size;
if (len = 0) then
begin
read_buf := 0;
exit;
end;
Dec(strm^.avail_in, len);
if deflate_state_ptr(strm^.state)^.noheader = 0 then
begin
strm^.adler := adler32(strm^.adler, strm^.next_in, len);
end;
zmemcpy(buf, strm^.next_in, len);
Inc(strm^.next_in, len);
Inc(strm^.total_in, len);
read_buf := int(len);
end;
{ ===========================================================================
Initialize the "longest match" routines for a new zlib stream }
{local}
procedure lm_init (var s : deflate_state);
begin
s.window_size := ulg( uLong(2)*s.w_size);
{macro CLEAR_HASH(s);}
s.head^[s.hash_size-1] := ZNIL;
zmemzero(pBytef(s.head), unsigned(s.hash_size-1)*sizeof(s.head^[0]));
{ Set the default configuration parameters: }
s.max_lazy_match := configuration_table[s.level].max_lazy;
s.good_match := configuration_table[s.level].good_length;
s.nice_match := configuration_table[s.level].nice_length;
s.max_chain_length := configuration_table[s.level].max_chain;
s.strstart := 0;
s.block_start := long(0);
s.lookahead := 0;
s.prev_length := MIN_MATCH-1;
s.match_length := MIN_MATCH-1;
s.match_available := FALSE;
s.ins_h := 0;
{$ifdef ASMV}
match_init; { initialize the asm code }
{$endif}
end;
{ ===========================================================================
Set match_start to the longest match starting at the given string and
return its length. Matches shorter or equal to prev_length are discarded,
in which case the result is equal to prev_length and match_start is
garbage.
IN assertions: cur_match is the head of the hash chain for the current
string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
OUT assertion: the match length is not greater than s^.lookahead. }
{$ifndef ASMV}
{ For 80x86 and 680x0, an optimized version will be provided in match.asm or
match.S. The code will be functionally equivalent. }
{$ifndef FASTEST}
{local}
function longest_match(var s : deflate_state;
cur_match : IPos { current match }
) : uInt;
label
nextstep;
var
chain_length : unsigned; { max hash chain length }
{register} scan : pBytef; { current string }
{register} match : pBytef; { matched string }
{register} len : int; { length of current match }
best_len : int; { best match length so far }
nice_match : int; { stop if match long enough }
limit : IPos;
prev : pzPosfArray;
wmask : uInt;
{$ifdef UNALIGNED_OK}
{register} strend : pBytef;
{register} scan_start : ush;
{register} scan_end : ush;
{$else}
{register} strend : pBytef;
{register} scan_end1 : Byte;
{register} scan_end : Byte;
{$endif}
var
MAX_DIST : uInt;
begin
chain_length := s.max_chain_length; { max hash chain length }
scan := @(s.window^[s.strstart]);
best_len := s.prev_length; { best match length so far }
nice_match := s.nice_match; { stop if match long enough }
MAX_DIST := s.w_size - MIN_LOOKAHEAD;
{In order to simplify the code, particularly on 16 bit machines, match
distances are limited to MAX_DIST instead of WSIZE. }
if s.strstart > IPos(MAX_DIST) then
limit := s.strstart - IPos(MAX_DIST)
else
limit := ZNIL;
{ Stop when cur_match becomes <= limit. To simplify the code,
we prevent matches with the string of window index 0. }
prev := s.prev;
wmask := s.w_mask;
{$ifdef UNALIGNED_OK}
{ Compare two bytes at a time. Note: this is not always beneficial.
Try with and without -DUNALIGNED_OK to check. }
strend := pBytef(@(s.window^[s.strstart + MAX_MATCH - 1]));
scan_start := pushf(scan)^;
scan_end := pushfArray(scan)^[best_len-1]; { fix }
{$else}
strend := pBytef(@(s.window^[s.strstart + MAX_MATCH]));
{$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
scan_end1 := pzByteArray(scan)^[best_len-1];
{$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
scan_end := pzByteArray(scan)^[best_len];
{$endif}
{ 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. }
{$IFDEF DEBUG}
Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever');
{$ENDIF}
{ Do not waste too much time if we already have a good match: }
if (s.prev_length >= s.good_match) then
begin
chain_length := chain_length shr 2;
end;
{ Do not look for matches beyond the end of the input. This is necessary
to make deflate deterministic. }
if (uInt(nice_match) > s.lookahead) then
nice_match := s.lookahead;
{$IFDEF DEBUG}
Assert(ulg(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead');
{$ENDIF}
repeat
{$IFDEF DEBUG}
Assert(cur_match < s.strstart, 'no future');
{$ENDIF}
match := @(s.window^[cur_match]);
{ Skip to next match if the match length cannot increase
or if the match length is less than 2: }
{$undef DO_UNALIGNED_OK}
{$ifdef UNALIGNED_OK}
{$ifdef MAX_MATCH_IS_258}
{$define DO_UNALIGNED_OK}
{$endif}
{$endif}
{$ifdef DO_UNALIGNED_OK}
{ This code assumes sizeof(unsigned short) = 2. Do not use
UNALIGNED_OK if your compiler uses a different size. }
{$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
if (pushfArray(match)^[best_len-1] <> scan_end) or
(pushf(match)^ <> scan_start) then
goto nextstep; {continue;}
{$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
{ 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. Compare 2 bytes at a time at
strstart+3, +5, ... up to strstart+257. We check for insufficient
lookahead only every 4th comparison; the 128th check will be made
at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
necessary to put more guard bytes at the end of the window, or
to check more often for insufficient lookahead. }
{$IFDEF DEBUG}
Assert(pzByteArray(scan)^[2] = pzByteArray(match)^[2], 'scan[2]?');
{$ENDIF}
Inc(scan);
Inc(match);
repeat
Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break;
Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break;
Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break;
Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break;
until (ptr2int(scan) >= ptr2int(strend));
{ The funny "do while" generates better code on most compilers }
{ Here, scan <= window+strstart+257 }
{$IFDEF DEBUG}
Assert(ptr2int(scan) <=
ptr2int(@(s.window^[unsigned(s.window_size-1)])),
'wild scan');
{$ENDIF}
if (scan^ = match^) then
Inc(scan);
len := (MAX_MATCH - 1) - int(ptr2int(strend)-ptr2int(scan));
scan := strend;
Dec(scan, (MAX_MATCH-1));
{$else} { UNALIGNED_OK }
{$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
if (pzByteArray(match)^[best_len] <> scan_end) or
(pzByteArray(match)^[best_len-1] <> scan_end1) or
(match^ <> scan^) then
goto nextstep; {continue;}
{$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
Inc(match);
if (match^ <> pzByteArray(scan)^[1]) then
goto nextstep; {continue;}
{ 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. }
Inc(scan, 2);
Inc(match);
{$IFDEF DEBUG}
Assert( scan^ = match^, 'match[2]?');
{$ENDIF}
{ We check for insufficient lookahead only every 8th comparison;
the 256th check will be made at strstart+258. }
repeat
Inc(scan); Inc(match); if (scan^ <> match^) then break;
Inc(scan); Inc(match); if (scan^ <> match^) then break;
Inc(scan); Inc(match); if (scan^ <> match^) then break;
Inc(scan); Inc(match); if (scan^ <> match^) then break;
Inc(scan); Inc(match); if (scan^ <> match^) then break;
Inc(scan); Inc(match); if (scan^ <> match^) then break;
Inc(scan); Inc(match); if (scan^ <> match^) then break;
Inc(scan); Inc(match); if (scan^ <> match^) then break;
until (ptr2int(scan) >= ptr2int(strend));
{$IFDEF DEBUG}
Assert(ptr2int(scan) <=
ptr2int(@(s.window^[unsigned(s.window_size-1)])),
'wild scan');
{$ENDIF}
len := MAX_MATCH - int(ptr2int(strend) - ptr2int(scan));
scan := strend;
Dec(scan, MAX_MATCH);
{$endif} { UNALIGNED_OK }
if (len > best_len) then
begin
s.match_start := cur_match;
best_len := len;
if (len >= nice_match) then
break;
{$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF}
{$ifdef UNALIGNED_OK}
scan_end := pzByteArray(scan)^[best_len-1];
{$else}
scan_end1 := pzByteArray(scan)^[best_len-1];
scan_end := pzByteArray(scan)^[best_len];
{$endif}
{$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF}
end;
nextstep:
cur_match := prev^[cur_match and wmask];
Dec(chain_length);
until (cur_match <= limit) or (chain_length = 0);
if (uInt(best_len) <= s.lookahead) then
longest_match := uInt(best_len)
else
longest_match := s.lookahead;
end;
{$endif} { ASMV }
{$else} { FASTEST }
{ ---------------------------------------------------------------------------
Optimized version for level = 1 only }
{local}
function longest_match(var s : deflate_state;
cur_match : IPos { current match }
) : uInt;
var
{register} scan : pBytef; { current string }
{register} match : pBytef; { matched string }
{register} len : int; { length of current match }
{register} strend : pBytef;
begin
scan := @s.window^[s.strstart];
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. }
{$IFDEF DEBUG}
Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever');
Assert(ulg(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead');
Assert(cur_match < s.strstart, 'no future');
{$ENDIF}
match := s.window + cur_match;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -