CentrED/Imaging/ZLib/iminfcodes.pas

577 lines
15 KiB
Plaintext
Raw Permalink Normal View History

2022-05-08 10:47:53 +02:00
Unit iminfcodes;
{ infcodes.c -- process literals and length/distance pairs
Copyright (C) 1995-1998 Mark Adler
Pascal tranlastion
Copyright (C) 1998 by Jacques Nomssi Nzali
For conditions of distribution and use, see copyright notice in readme.txt
}
interface
{$I imzconf.inc}
uses
{$IFDEF DEBUG}
SysUtils, strutils,
{$ENDIF}
imzutil, impaszlib;
function inflate_codes_new (bl : uInt;
bd : uInt;
tl : pInflate_huft;
td : pInflate_huft;
var z : z_stream): pInflate_codes_state;
function inflate_codes(var s : inflate_blocks_state;
var z : z_stream;
r : int) : int;
procedure inflate_codes_free(c : pInflate_codes_state;
var z : z_stream);
implementation
uses
iminfutil, iminffast;
function inflate_codes_new (bl : uInt;
bd : uInt;
tl : pInflate_huft;
td : pInflate_huft;
var z : z_stream): pInflate_codes_state;
var
c : pInflate_codes_state;
begin
c := pInflate_codes_state( ZALLOC(z,1,sizeof(inflate_codes_state)) );
if (c <> Z_NULL) then
begin
c^.mode := START;
c^.lbits := Byte(bl);
c^.dbits := Byte(bd);
c^.ltree := tl;
c^.dtree := td;
{$IFDEF DEBUG}
Tracev('inflate: codes new');
{$ENDIF}
end;
inflate_codes_new := c;
end;
function inflate_codes(var s : inflate_blocks_state;
var z : z_stream;
r : int) : int;
var
j : uInt; { temporary storage }
t : pInflate_huft; { temporary pointer }
e : uInt; { extra bits or operation }
b : uLong; { bit buffer }
k : uInt; { bits in bit buffer }
p : pBytef; { input data pointer }
n : uInt; { bytes available there }
q : pBytef; { output window write pointer }
m : uInt; { bytes to end of window or read pointer }
f : pBytef; { pointer to copy strings from }
var
c : pInflate_codes_state;
begin
c := s.sub.decode.codes; { codes state }
{ copy input/output information to locals }
p := z.next_in;
n := z.avail_in;
b := s.bitb;
k := s.bitk;
q := s.write;
if ptr2int(q) < ptr2int(s.read) then
m := uInt(ptr2int(s.read)-ptr2int(q)-1)
else
m := uInt(ptr2int(s.zend)-ptr2int(q));
{ process input and output based on current state }
while True do
case (c^.mode) of
{ waiting for "i:"=input, "o:"=output, "x:"=nothing }
START: { x: set up for LEN }
begin
{$ifndef SLOW}
if (m >= 258) and (n >= 10) then
begin
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
r := inflate_fast(c^.lbits, c^.dbits, c^.ltree, c^.dtree, s, z);
{LOAD}
p := z.next_in;
n := z.avail_in;
b := s.bitb;
k := s.bitk;
q := s.write;
if ptr2int(q) < ptr2int(s.read) then
m := uInt(ptr2int(s.read)-ptr2int(q)-1)
else
m := uInt(ptr2int(s.zend)-ptr2int(q));
if (r <> Z_OK) then
begin
if (r = Z_STREAM_END) then
c^.mode := WASH
else
c^.mode := BADCODE;
continue; { break for switch-statement in C }
end;
end;
{$endif} { not SLOW }
c^.sub.code.need := c^.lbits;
c^.sub.code.tree := c^.ltree;
c^.mode := LEN; { falltrough }
end;
LEN: { i: get length/literal/eob next }
begin
j := c^.sub.code.need;
{NEEDBITS(j);}
while (k < j) do
begin
{NEEDBYTE;}
if (n <> 0) then
r :=Z_OK
else
begin
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
Dec(n);
b := b or (uLong(p^) shl k);
Inc(p);
Inc(k, 8);
end;
t := c^.sub.code.tree;
Inc(t, uInt(b) and inflate_mask[j]);
{DUMPBITS(t^.bits);}
b := b shr t^.bits;
Dec(k, t^.bits);
e := uInt(t^.exop);
if (e = 0) then { literal }
begin
c^.sub.lit := t^.base;
{$IFDEF DEBUG}
if (t^.base >= $20) and (t^.base < $7f) then
Tracevv('inflate: literal '+AnsiChar(t^.base))
else
Tracevv('inflate: literal '+IntToStr(t^.base));
{$ENDIF}
c^.mode := LIT;
continue; { break switch statement }
end;
if (e and 16 <> 0) then { length }
begin
c^.sub.copy.get := e and 15;
c^.len := t^.base;
c^.mode := LENEXT;
continue; { break C-switch statement }
end;
if (e and 64 = 0) then { next table }
begin
c^.sub.code.need := e;
c^.sub.code.tree := @huft_ptr(t)^[t^.base];
continue; { break C-switch statement }
end;
if (e and 32 <> 0) then { end of block }
begin
{$IFDEF DEBUG}
Tracevv('inflate: end of block');
{$ENDIF}
c^.mode := WASH;
continue; { break C-switch statement }
end;
c^.mode := BADCODE; { invalid code }
z.msg := 'invalid literal/length code';
r := Z_DATA_ERROR;
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
LENEXT: { i: getting length extra (have base) }
begin
j := c^.sub.copy.get;
{NEEDBITS(j);}
while (k < j) do
begin
{NEEDBYTE;}
if (n <> 0) then
r :=Z_OK
else
begin
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
Dec(n);
b := b or (uLong(p^) shl k);
Inc(p);
Inc(k, 8);
end;
Inc(c^.len, uInt(b and inflate_mask[j]));
{DUMPBITS(j);}
b := b shr j;
Dec(k, j);
c^.sub.code.need := c^.dbits;
c^.sub.code.tree := c^.dtree;
{$IFDEF DEBUG}
Tracevv('inflate: length '+IntToStr(c^.len));
{$ENDIF}
c^.mode := DIST;
{ falltrough }
end;
DIST: { i: get distance next }
begin
j := c^.sub.code.need;
{NEEDBITS(j);}
while (k < j) do
begin
{NEEDBYTE;}
if (n <> 0) then
r :=Z_OK
else
begin
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
Dec(n);
b := b or (uLong(p^) shl k);
Inc(p);
Inc(k, 8);
end;
t := @huft_ptr(c^.sub.code.tree)^[uInt(b) and inflate_mask[j]];
{DUMPBITS(t^.bits);}
b := b shr t^.bits;
Dec(k, t^.bits);
e := uInt(t^.exop);
if (e and 16 <> 0) then { distance }
begin
c^.sub.copy.get := e and 15;
c^.sub.copy.dist := t^.base;
c^.mode := DISTEXT;
continue; { break C-switch statement }
end;
if (e and 64 = 0) then { next table }
begin
c^.sub.code.need := e;
c^.sub.code.tree := @huft_ptr(t)^[t^.base];
continue; { break C-switch statement }
end;
c^.mode := BADCODE; { invalid code }
z.msg := 'invalid distance code';
r := Z_DATA_ERROR;
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
DISTEXT: { i: getting distance extra }
begin
j := c^.sub.copy.get;
{NEEDBITS(j);}
while (k < j) do
begin
{NEEDBYTE;}
if (n <> 0) then
r :=Z_OK
else
begin
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
Dec(n);
b := b or (uLong(p^) shl k);
Inc(p);
Inc(k, 8);
end;
Inc(c^.sub.copy.dist, uInt(b) and inflate_mask[j]);
{DUMPBITS(j);}
b := b shr j;
Dec(k, j);
{$IFDEF DEBUG}
Tracevv('inflate: distance '+ IntToStr(c^.sub.copy.dist));
{$ENDIF}
c^.mode := COPY;
{ falltrough }
end;
COPY: { o: copying bytes in window, waiting for space }
begin
f := q;
Dec(f, c^.sub.copy.dist);
if (uInt(ptr2int(q) - ptr2int(s.window)) < c^.sub.copy.dist) then
begin
f := s.zend;
Dec(f, c^.sub.copy.dist - uInt(ptr2int(q) - ptr2int(s.window)));
end;
while (c^.len <> 0) do
begin
{NEEDOUT}
if (m = 0) then
begin
{WRAP}
if (q = s.zend) and (s.read <> s.window) then
begin
q := s.window;
if ptr2int(q) < ptr2int(s.read) then
m := uInt(ptr2int(s.read)-ptr2int(q)-1)
else
m := uInt(ptr2int(s.zend)-ptr2int(q));
end;
if (m = 0) then
begin
{FLUSH}
s.write := q;
r := inflate_flush(s,z,r);
q := s.write;
if ptr2int(q) < ptr2int(s.read) then
m := uInt(ptr2int(s.read)-ptr2int(q)-1)
else
m := uInt(ptr2int(s.zend)-ptr2int(q));
{WRAP}
if (q = s.zend) and (s.read <> s.window) then
begin
q := s.window;
if ptr2int(q) < ptr2int(s.read) then
m := uInt(ptr2int(s.read)-ptr2int(q)-1)
else
m := uInt(ptr2int(s.zend)-ptr2int(q));
end;
if (m = 0) then
begin
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
end;
end;
r := Z_OK;
{OUTBYTE( *f++)}
q^ := f^;
Inc(q);
Inc(f);
Dec(m);
if (f = s.zend) then
f := s.window;
Dec(c^.len);
end;
c^.mode := START;
{ C-switch break; not needed }
end;
LIT: { o: got literal, waiting for output space }
begin
{NEEDOUT}
if (m = 0) then
begin
{WRAP}
if (q = s.zend) and (s.read <> s.window) then
begin
q := s.window;
if ptr2int(q) < ptr2int(s.read) then
m := uInt(ptr2int(s.read)-ptr2int(q)-1)
else
m := uInt(ptr2int(s.zend)-ptr2int(q));
end;
if (m = 0) then
begin
{FLUSH}
s.write := q;
r := inflate_flush(s,z,r);
q := s.write;
if ptr2int(q) < ptr2int(s.read) then
m := uInt(ptr2int(s.read)-ptr2int(q)-1)
else
m := uInt(ptr2int(s.zend)-ptr2int(q));
{WRAP}
if (q = s.zend) and (s.read <> s.window) then
begin
q := s.window;
if ptr2int(q) < ptr2int(s.read) then
m := uInt(ptr2int(s.read)-ptr2int(q)-1)
else
m := uInt(ptr2int(s.zend)-ptr2int(q));
end;
if (m = 0) then
begin
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
end;
end;
r := Z_OK;
{OUTBYTE(c^.sub.lit);}
q^ := c^.sub.lit;
Inc(q);
Dec(m);
c^.mode := START;
{break;}
end;
WASH: { o: got eob, possibly more output }
begin
{$ifdef patch112}
if (k > 7) then { return unused byte, if any }
begin
{$IFDEF DEBUG}
Assert(k < 16, 'inflate_codes grabbed too many bytes');
{$ENDIF}
Dec(k, 8);
Inc(n);
Dec(p); { can always return one }
end;
{$endif}
{FLUSH}
s.write := q;
r := inflate_flush(s,z,r);
q := s.write;
if ptr2int(q) < ptr2int(s.read) then
m := uInt(ptr2int(s.read)-ptr2int(q)-1)
else
m := uInt(ptr2int(s.zend)-ptr2int(q));
if (s.read <> s.write) then
begin
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
c^.mode := ZEND;
{ falltrough }
end;
ZEND:
begin
r := Z_STREAM_END;
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
BADCODE: { x: got error }
begin
r := Z_DATA_ERROR;
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
else
begin
r := Z_STREAM_ERROR;
{UPDATE}
s.bitb := b;
s.bitk := k;
z.avail_in := n;
Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in));
z.next_in := p;
s.write := q;
inflate_codes := inflate_flush(s,z,r);
exit;
end;
end;
{NEED_DUMMY_RETURN - Delphi2+ dumb compilers complain without this }
inflate_codes := Z_STREAM_ERROR;
end;
procedure inflate_codes_free(c : pInflate_codes_state;
var z : z_stream);
begin
ZFREE(z, c);
{$IFDEF DEBUG}
Tracev('inflate: codes free');
{$ENDIF}
end;
end.