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.