mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-11-13 16:59:36 +01:00
other zlib package
* paszlib unit added as generic interface for all other units, this
unit is partly compatible with the other zlib pacakge
576 lines
15 KiB
ObjectPascal
576 lines
15 KiB
ObjectPascal
Unit InfCodes;
|
|
|
|
{ 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 zconf.inc}
|
|
|
|
uses
|
|
{$IFDEF DEBUG}
|
|
strutils,
|
|
{$ENDIF}
|
|
zutil, zbase;
|
|
|
|
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
|
|
infutil, inffast;
|
|
|
|
|
|
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 '+char(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. |