123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017 |
- { Copyright (C) <2005> <Andrew Haines> paslzx.pas
- This library is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published by
- the Free Software Foundation; either version 2 of the License, or (at your
- option) any later version.
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
- for more details.
- You should have received a copy of the GNU Library General Public License
- along with this library; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- }
- {
- See the file COPYING.LCL, included in this distribution,
- for details about the copyright.
- }
- {***************************************************************************
- * paslzx.pas - LZX decompression routines *
- * ------------------- *
- * *
- * maintainer: Andrew Haines <[email protected]> *
- * source: modified lzx.c from chmlib 0.37-4 *
- * notes: The lzx.c file was taken from cabextract v0.5, which was, *
- * itself, a modified version of the lzx decompression code *
- * from unlzx. This file would not be available without the *
- * invaluable help from Micha Nelissen fixing my errors. *
- * *
- * Licensed with permission of Stuart Caie with a modified *
- * LGPL. *
- * *
- * platforms: Should work on any platform that FreePascal is available *
- * on. However it has been tested on only an amd64(Linux) and *
- * x86(Linux and Windows). Only tested on little endian pc's. *
- ***************************************************************************}
- unit paslzx;
- {$mode objfpc}{$H+}{$R+}
- interface
- uses
- Classes, SysUtils;
-
- const
- DECR_OK = 0;
- DECR_DATAFORMAT = 1;
- DECR_ILLEGALDATA = 2;
- DECR_NOMEMORY = 3;
-
-
- // some constants defined by the LZX specification
- LZX_MIN_MATCH = 2;
- LZX_MAX_MATCH = 257;
- LZX_NUM_CHARS = 256;
- LZX_BLOCKTYPE_INVALID = 0; // also blocktypes 4-7 invalid
- LZX_BLOCKTYPE_VERBATIM = 1;
- LZX_BLOCKTYPE_ALIGNED = 2;
- LZX_BLOCKTYPE_UNCOMPRESSED= 3;
- LZX_PRETREE_NUM_ELEMENTS = 20;
- LZX_ALIGNED_NUM_ELEMENTS = 8; // aligned offset tree #elements
- LZX_NUM_PRIMARY_LENGTHS = 7; // this one missing from spec!
- LZX_NUM_SECONDARY_LENGTHS = 249;// length tree #elements
-
- // LZX huffman defines: tweak tablebits as desired
- LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS;
- LZX_PRETREE_TABLEBITS = 6;
- LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 50*8;
- LZX_MAINTREE_TABLEBITS = 12;
- LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS+1;
- LZX_LENGTH_TABLEBITS = 12;
- LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
- LZX_ALIGNED_TABLEBITS = 7;
- LZX_LENTABLE_SAFETY = 64; // we allow length table decoding overruns
-
- extra_bits: array [0..50] of Byte = (
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
- 15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17
- );
-
- position_base: array [0..50] of dword = (
- 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
- 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
- 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
- 1835008, 1966080, 2097152
- );
- type
- { TBits }
- TBufBits = class
- private
- bitbuf: dword;
- bitsleft: LongInt;
- public
- procedure Init;
- procedure ensure(num: LongInt; var inpos:PByte);
- function peek(numbits: LongInt): dword;
- function remove(numbits: LongInt): dword;
- function read(numbits: LongInt; var inpos: PByte): dword;
- end;
- TLZX_PRETREE_TABLE = record
- Table: array [0..(1 shl LZX_PRETREE_TABLEBITS) + (LZX_PRETREE_MAXSYMBOLS shl 1)-1] of Word;
- Len: array [0..LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY-1] of Byte;
- end;
- TLZX_MAINTREE_TABLE = record
- Table: array [0..(1 shl LZX_MAINTREE_TABLEBITS) + (LZX_MAINTREE_MAXSYMBOLS shl 1)-1] of Word;
- Len: array [0..LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY-1] of Byte;
- end;
- TLZX_LENGTH_TABLE = record
- Table: array [0..(1 shl LZX_LENGTH_TABLEBITS) + (LZX_LENGTH_MAXSYMBOLS shl 1)-1] of Word;
- Len: array [0..LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY-1] of Byte;
- end;
- TLZX_ALIGNED_TABLE = record
- Table: array [0..(1 shl LZX_ALIGNED_TABLEBITS) + (LZX_ALIGNED_MAXSYMBOLS shl 1)-1] of Word;
- Len: array [0..LZX_ALIGNED_MAXSYMBOLS + LZX_LENTABLE_SAFETY-1] of Byte;
- end;
- PLZXState = ^TLZXState;
- TLZXState = record
- window: PByte; // the actual decoding window
- window_size, // window size (32Kb through 2Mb)
- actual_size, // window size when it was first allocated
- window_posn, // current offset within the window
- R0, R1, R2: dword; // for the LRU offset system
- main_elements : Word; // number of main tree elements
- header_read: LongInt; // have we started decoding at all yet?
- block_type: Word; // type of this block
- block_length, // uncompressed length of this block
- block_remaining, // uncompressed bytes still left to decode
- frames_read: dword; // the number of CFDATA blocks
- intel_filesize, // magic header value used for transform
- intel_curpos: LongInt; // current offset in transform space
- intel_started: LongInt; // have we seen any translatable data yet?
- PreTreeTable: TLZX_PRETREE_TABLE;
- MainTreeTable: TLZX_MAINTREE_TABLE;
- LengthTable: TLZX_LENGTH_TABLE;
- AlignedTAble: TLZX_ALIGNED_TABLE;
- end;
-
- // create an lzx state object
- function LZXinit(window: LongInt): PLZXState;
-
- // destroy an lzx state object
- procedure LZXteardown(pState: PLZXState);
-
- // reset an lzx stream
- function LZXreset(pState: PLZXState): LongInt;
-
- function LZXdecompress(pState: PLZXstate; inpos, outpos: PByte; inlen, outlen: LongInt): LongInt;
- implementation
- const
- ULONG_BITS = sizeof(LongInt)shl 3;
-
- function make_decode_table(nsyms: dword; nbits: dword; length: PByte; table: PWord): LongInt;
- var
- Sym: Word;
- leaf: dword;
- bit_num: Byte = 1;
- fill: dword;
- pos: dword = 0; //* the current position in the decode table */
- table_mask: dword;
- bit_mask: dword; //* don't do 0 length codes */
- next_symbol: dword; //* base of allocation for long codes */
- begin
- Result := 0;
- table_mask := 1 shl nbits;
- bit_mask := table_mask shr 1;
- next_symbol := bit_mask;
- //* fill entries for codes short enough for a direct mapping */
- while (bit_num <= nbits) do begin
- for sym := 0 to nsyms-1 do begin
- if (length[sym] = bit_num) then begin
- leaf := pos;
- Inc(pos, bit_mask);
- if pos > table_mask then begin
- Result := 1; //* table overrun */
- exit;
- end;
- //* fill all possible lookups of this symbol with the symbol itself */
- fill := bit_mask;
- while fill > 0 do
- begin
- dec(fill);
- table[leaf] := sym;
- Inc(leaf);
- end;
- end;
- end;
- bit_mask := bit_mask shr 1;
- Inc(bit_num);
- end;
- //* if there are any codes longer than nbits */
- if pos <> table_mask then begin
- //* clear the remainder of the table */
- for sym := pos to table_mask-1 do table[sym] := 0;
- //* give ourselves room for codes to grow by up to 16 more bits */
- pos := pos shl 16;
- table_mask := table_mask shl 16;
- bit_mask := 1 shl 15;
- while (bit_num <= 16) do begin
- for sym := 0 to nsyms-1 do begin
- if (length[sym] = bit_num) then begin
- leaf := pos shr 16;
- for fill := 0 to (bit_num - nbits)-1 do begin
- //* if this path hasn't been taken yet, 'allocate' two entries */
- if (table[leaf] = 0) then begin
- table[(next_symbol shl 1)] := 0;
- table[(next_symbol shl 1)+1] := 0;
- table[leaf] := Word(next_symbol);
- Inc(next_symbol);
- end;
- //* follow the path and select either left or right for next bit */
- leaf := table[leaf] shl 1;
- if ((pos shr (15-fill)) and 1) > 0 then Inc(leaf);
- end;
- table[leaf] := sym;
- pos := pos + bit_mask;
- if (pos > table_mask) then begin
- Result := 1; //* table overflow */
- exit;
- end;
- end;
- end;
- bit_mask := bit_mask shr 1;
- Inc(bit_num);
- end;
- end;
- //* full table? */
- if (pos = table_mask) then begin
- Result := 0;
- Exit;
- end;
- //* either erroneous table, or all elements are 0 - let's find out. */
- for sym := 0 to nsyms-1 do begin
- if length[sym] > 0 then begin
- Result := 1;
- Exit;
- end;
- end;
- Result := 0;
- end;
- type
- PLZX_bits = ^TLzx_bits;
- Tlzx_bits = record
- bb: dword;
- bl: LongInt;
- ip: PByte;
- end;
- function READ_HUFFSYM(Table: PWord; Len: PByte; const bits: TBufBits; var inpos: PByte;
- var i, j: DWord; const TableBits, MaxSymbols: DWord; out z: LongInt): LongInt;
- var
- hufftbl: PWord;
- begin
- bits.ensure(16, inpos);
- hufftbl := Table;
- i := hufftbl[bits.peek(TableBits)];
- if (i) >= MaxSymbols then begin
- j := 1 shl (ULONG_BITS - TableBits);
- repeat
- j := j shr 1;
- i := i shl 1;
- i := i or ord((bits.bitbuf and j) <> 0);
- if j = 0 then begin
- Result := DECR_ILLEGALDATA;
- Exit;
- end;
- i := hufftbl[i];
- until i < MaxSymbols;
- end;
- z := i;
- j := Len[z];
- bits.remove(j);
- Result := 0;
- end;
- function lzx_read_lens(pState: PLZXState; lens: PByte; first: dword; last: dword; lb: Plzx_bits): LongInt;
- var
- i: dword = 0;
- j: dword = 0;
- x,y: dword;
- z: LongInt;
- inpos: PByte;
- bits: TBufBits;
- begin
- bits := TBufBits.Create;
- bits.bitbuf := lb^.bb;
- bits.bitsleft := lb^.bl;
-
- inpos := lb^.ip;
- for X := 0 to 19 do begin
- y := bits.read(4, inpos);
- pState^.PreTreeTable.Len[x] := byte(y);
- end;
- if make_decode_table(LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS,
- @pState^.PreTreeTable.Len[0],@pState^.PreTreeTable.Table[0]) >0 then
- begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- x := first;
- while x < last do begin
- if READ_HUFFSYM(@pState^.PreTreeTable.Table[0], @pstate^.PreTreeTable.Len[0], bits, inpos, i, j,
- LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, z) <> 0 then
- begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- if (z = 17) then begin
- y := bits.read(4, inpos);
- Inc(y, 4);
- while y > 0 do begin
- dec(y);
- Lens[x] := 0;
- Inc(x);
- end;
- end
- else if (z = 18) then begin
- y := bits.read(5, inpos);
- Inc(y, 20);
- while y > 0 do begin
- dec(y);
- lens[x] := 0;
- inc(x);
- end;
- end
- else if (z = 19) then begin
- y := bits.read(1, inpos);
- Inc(y, 4);
- if READ_HUFFSYM(@pState^.PreTreeTable.Table[0], @pstate^.PreTreeTable.Len[0], bits, inpos, i, j,
- LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, z) <> 0 then
- begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- z := lens[x] - z;
- if (z < 0) then z := z + 17;
- while y > 0 do begin
- dec(y);
- lens[x] := byte(z);
- inc(x);
- end;
- end
- else begin
- z := lens[x] - z;
- if (z < 0) then z := z + 17;
- lens[x] := byte(z);
- inc(x);
- end;
- end;
- lb^.bb := bits.bitbuf;
- lb^.bl := bits.bitsleft;
- lb^.ip := inpos;
- Result := 0;
- bits.Free;
- end;
-
-
- //////////////////////////////////////////////////////////////////////////////////////
- function LZXinit(window: LongInt): PLZXState;
- var
- pState: PLZXState;
- wndsize: dword;
- i,
- posn_slots: LongInt;
- begin
- Result := nil;
- wndsize := 1 shl window;
- //* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
- //* if a previously allocated window is big enough, keep it */
- if (window < 15) or (window > 21) then begin
- Exit;
- end;
- //* allocate state and associated window */
- New(pState);
- pState^.window := GetMem(wndsize);
- if pState^.window = nil then
- begin
- Dispose(pState);
- Result := nil;
- exit;
- end;
- pState^.actual_size := wndsize;
- pState^.window_size := wndsize;
- //* calculate required position slots */
- if (window = 20) then posn_slots := 42
- else if (window = 21) then posn_slots := 50
- else posn_slots := window shl 1;
- ///** alternatively **/
- ///* posn_slots=i=0; while (i < wndsize) i += 1 << extra_bits[posn_slots++]; */
- ///* initialize other state */
- pState^.R0 := 1;
- pState^.R1 := 1;
- pState^.R2 := 1;
-
- pState^.main_elements := LZX_NUM_CHARS + (posn_slots shl 3);
- pState^.header_read := 0;
- pState^.frames_read := 0;
- pState^.block_remaining := 0;
- pState^.block_type := LZX_BLOCKTYPE_INVALID;
- pState^.intel_curpos := 0;
- pState^.intel_started := 0;
- pState^.window_posn := 0;
- ///* initialise tables to 0 (because deltas will be applied to them) */
- for i := 0 to LZX_MAINTREE_MAXSYMBOLS-1 do pState^.MainTreeTable.Len[i] := 0;
- for i := 0 to LZX_LENGTH_MAXSYMBOLS-1 do pState^.LengthTable.Len[i] := 0;
- Result := pState;
- end;
- procedure LZXteardown(pState: PLZXState);
- begin
- if pState <> nil then
- begin
- if pState^.window <> nil then
- Freemem(pState^.window);
- Dispose(pState);
- end;
- end;
- function LZXreset(pState: PLZXState): LongInt;
- var
- i: LongInt;
- begin
- pState^.R0 := 1;
- pState^.R1 := 1;
- pState^.R2 := 1;
- pState^.header_read := 0;
- pState^.frames_read := 0;
- pState^.block_remaining := 0;
- pState^.block_type := LZX_BLOCKTYPE_INVALID;
- pState^.intel_curpos := 0;
- pState^.intel_started := 0;
- pState^.window_posn := 0;
- for i := 0 to (LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY - 1) do pState^.MainTreeTable.Len[i] := 0;
- for i := 0 to LZX_LENGTH_MAXSYMBOLS+LZX_LENTABLE_SAFETY-1 do pState^.LengthTable.Len[i] := 0;
- Result := DECR_OK;
- end;
- function LZXdecompress(pState: PLZXstate; inpos, outpos: PByte; inlen,
- outlen: LongInt): LongInt;
- var
- endinp: PByte;
- window: PByte;
- runsrc,
- rundest: PByte;
- window_posn: dword;
- window_size: dword;
- R0,
- r1,
- R2: dword;
- bits: TBufBits;
- match_offset,
- i,j,k : dword;
- lb: tlzx_bits;
- togo,
- this_run,
- main_element,
- aligned_bits: LongInt;
- match_length,
- length_footer,
- extra,
- verbatim_bits: LongInt;
- data,
- dataend: PByte;
- curpos,
- filesize,
- abs_off,
- rel_off: LongInt;
- function READ_LENGTHS(Len: PByte; first: dword; last: dword): Longint;
- begin
- Result := 0;
- lb.bb := bits.bitbuf;
- lb.bl := bits.bitsleft;
- lb.ip := inpos;
- if (lzx_read_lens(pState, Len,first,last,@lb)) > 0 then begin
- Result := DECR_ILLEGALDATA;
- Exit;
- end;
- bits.bitbuf := lb.bb;
- bits.bitsleft := lb.bl;
- inpos := lb.ip;
- end;
- procedure HandleBlockTypeAligned;
- var
- i, j: dword;
- begin
- for i := 0 to 7 do begin
- j:= bits.read(3, inpos);
- pState^.AlignedTAble.Len[i] := Word(j);
- end;
- if make_decode_table(LZX_ALIGNED_MAXSYMBOLS, LZX_ALIGNED_TABLEBITS,
- @pState^.AlignedTAble.Len[0],@pState^.AlignedTAble.Table[0]) >0 then
- begin
- Result := DECR_ILLEGALDATA;
- Exit;
- end;
- end;
- procedure HandleBlockTypeVerbatim;
- begin
- if (
- READ_LENGTHS(@pState^.MainTreeTable.Len[0], 0, 256) = DECR_ILLEGALDATA)
- or (
- READ_LENGTHS(@pState^.MainTreeTable.Len[0], 256, pState^.main_elements) = DECR_ILLEGALDATA)
- then begin
- Result := DECR_ILLEGALDATA;
- Exit;
- end;
- if make_decode_table(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS,
- @pState^.MainTreeTable.Len[0], @pState^.MainTreeTable.Table[0]) >0 then
- begin
- Result := DECR_ILLEGALDATA;
- Exit;
- end;
- if pState^.MainTreeTable.Len[$E8] <> 0 then
- pState^.intel_started := 1;
- if READ_LENGTHS(@pState^.LengthTable.Len[0], 0, LZX_NUM_SECONDARY_LENGTHS) = DECR_ILLEGALDATA then begin
- Result := DECR_ILLEGALDATA;
- Exit;
- end;
- if make_decode_table(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS,
- @pState^.LengthTable.Len[0],@pState^.LengthTable.Table[0]) >0 then
- begin
- Result := DECR_ILLEGALDATA;
- Exit;
- end;
- end;
-
- begin
- endinp := inpos + inlen;
- window := pState^.window;
- window_posn := pState^.window_posn;
- window_size := pState^.window_size;
- R0 := pState^.R0;
- R1 := pState^.R1;
- R2 := pState^.R2;
-
- togo := outlen;//, this_run, main_element, aligned_bits;
- bits := TBufBits.Create;
- bits.Init;
- //* read header if necessary */
- if (pState^.header_read) = 0 then begin
- i := 0;
- j := 0;
- k := bits.read(1, inpos);
- if (k) > 0 then begin
- i := bits.read(16, inpos);
- j := bits.read(16, inpos);
- end;
- pState^.intel_filesize := (i shl 16) or j; ///* or 0 if not encoded */
- pState^.header_read := 1;
- end;
- ///* main decoding loop */
- while (togo > 0) do begin
- ///* last block finished, new block expected */
- if (pState^.block_remaining = 0) then begin
- if (pState^.block_type = LZX_BLOCKTYPE_UNCOMPRESSED) then begin
- if (pState^.block_length and 1) > 0 then Inc(inpos); //* realign bitstream to word */
- bits.Init;
- end;
- pState^.block_type := Word(bits.read(3, inpos));
- i := bits.read(16, inpos);
- j := bits.read(8, inpos);
-
- pState^.block_length := (i shl 8) or j;
- pState^.block_remaining := pState^.block_length;
- case (pState^.block_type) of
- LZX_BLOCKTYPE_ALIGNED:
- begin
- HandleBlockTypeAligned;
- //* rest of aligned header is same as verbatim */
- HandleBlockTypeVerbatim;
- end;
- LZX_BLOCKTYPE_VERBATIM:
- begin
- HandleBlockTypeVerbatim;
- end;
- LZX_BLOCKTYPE_UNCOMPRESSED:
- begin
- pState^.intel_started := 1; //* because we can't assume otherwise */
- bits.ensure(16, inpos); //* get up to 16 pad bits into the buffer */
- if (bits.bitsleft > 16) then Dec(inpos ,2); //* and align the bitstream! */
- R0 := inpos[0] or (inpos[1]shl 8)or(inpos[2]shl 16)or(inpos[3]shl 24);
- Inc(inpos,4);
- R1 := inpos[0] or (inpos[1]shl 8)or(inpos[2]shl 16)or(inpos[3]shl 24);
- Inc(inpos,4);
- R2 := inpos[0] or (inpos[1]shl 8)or(inpos[2]shl 16)or(inpos[3]shl 24);
- Inc(inpos,4);
- end;
- else
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- end;
- //* buffer exhaustion check */
- if (inpos > endinp) then begin
- {* it's possible to have a file where the next run is less than
- * 16 bits in size. In this case, the READ_HUFFSYM() macro used
- * in building the tables will exhaust the buffer, so we should
- * allow for this, but not allow those accidentally read bits to
- * be used (so we check that there are at least 16 bits
- * remaining - in this boundary case they aren't really part of
- * the compressed data)
- *}
- if (inpos > (endinp+2)) or (bits.bitsleft < 16) then begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- end;
- this_run := pState^.block_remaining;
- while (this_run > 0) and (togo > 0) do begin
- if (this_run > togo) then this_run := togo;
- Dec(togo, this_run);
- Dec(pState^.block_remaining, this_run);
- //* apply 2^x-1 mask */
- window_posn := window_posn and (window_size - 1);
- //* runs can't straddle the window wraparound */
- if ((window_posn + this_run) > window_size) then begin
- Result := DECR_DATAFORMAT;
- bits.Free;
- Exit;
- end;
- case (pState^.block_type) of
- LZX_BLOCKTYPE_VERBATIM:
- begin
- while (this_run > 0) do begin
- if READ_HUFFSYM(@pState^.MainTreeTable.Table[0], @pState^.MainTreeTable.Len[0],
- bits, inpos, i, j, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS,
- main_element) <> 0 then
- begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- if (main_element < LZX_NUM_CHARS) then begin
- //* literal: 0 to LZX_NUM_CHARS-1 */
- window[window_posn] := Byte(main_element);
- Inc(window_posn);
- Dec(this_run);
- end
- else begin
- //* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
- Dec(main_element, LZX_NUM_CHARS);
- match_length := main_element and LZX_NUM_PRIMARY_LENGTHS;
- if (match_length = LZX_NUM_PRIMARY_LENGTHS) then begin
- if READ_HUFFSYM(@pState^.LengthTable.Table[0], @pState^.LengthTable.Len[0],
- bits, inpos, i, j, LZX_LENGTH_TABLEBITS, LZX_LENGTH_MAXSYMBOLS,
- length_footer) <> 0 then
- begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- Inc(match_length, length_footer);
- end;
- Inc(match_length, LZX_MIN_MATCH);
- match_offset := main_element shr 3;
- if (match_offset > 2) then begin
- //* not repeated offset */
- if (match_offset <> 3) then begin
- extra := extra_bits[match_offset];
- verbatim_bits := bits.read(extra, inpos);
- match_offset := position_base[match_offset] - 2 + verbatim_bits;
- end
- else begin
- match_offset := 1;
- end;
- //* update repeated offset LRU queue */
- R2 := R1;
- R1 := R0;
- R0 := match_offset;
- end
- else if (match_offset = 0) then begin
- match_offset := R0;
- end
- else if (match_offset = 1) then begin
- match_offset := R1;
- R1 := R0;
- R0 := match_offset;
- end
- else begin //* match_offset == 2 */
- match_offset := R2;
- R2 := R0;
- R0 := match_offset;
- end;
- rundest := window + window_posn;
- runsrc := rundest - match_offset;
- Inc(window_posn, match_length);
- if (window_posn > window_size) then begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- Dec(this_run, match_length);
- ///* copy any wrapped around source data */
- while ((runsrc < window) and (match_length > 0)) do begin
- Dec(match_length);
- rundest^ := (runsrc + window_size)^;
- Inc(rundest);
- Inc(runsrc);
- end;
- //* copy match data - no worries about destination wraps */
- while (match_length > 0) do begin
- Dec(match_length);
- rundest^ := runsrc^;
- Inc(rundest);
- Inc(runsrc);
- end;
- end
- end;
- end;
- LZX_BLOCKTYPE_ALIGNED:
- begin
- while (this_run > 0) do begin
- if READ_HUFFSYM(@pState^.MainTreeTable.Table[0], @pState^.MainTreeTable.Len[0], bits,
- inpos, i, j, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS, main_element) <> 0 then
- begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- if (main_element < LZX_NUM_CHARS) then begin
- //* literal: 0 to LZX_NUM_CHARS-1 */
- window[window_posn] := Byte(main_element);
- Inc(window_posn);
- Dec(this_run);
- end
- else begin
- //* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
- Dec(main_element, LZX_NUM_CHARS);
- match_length := main_element and LZX_NUM_PRIMARY_LENGTHS;
- if (match_length = LZX_NUM_PRIMARY_LENGTHS) then begin
- if READ_HUFFSYM(@pState^.LengthTable.Table[0], @pState^.LengthTable.Len[0],
- bits, inpos, i, j, LZX_LENGTH_TABLEBITS,
- LZX_LENGTH_MAXSYMBOLS, length_footer) <> 0 then
- begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- Inc(match_length, length_footer);
- end;
- Inc(match_length, LZX_MIN_MATCH);
- match_offset := main_element shr 3;
- if (match_offset > 2) then begin
- //* not repeated offset */
- extra := extra_bits[match_offset];
- match_offset := position_base[match_offset] - 2;
- if (extra > 3) then begin
- //* verbatim and aligned bits */
- Dec(extra, 3);
- verbatim_bits := bits.read(extra, inpos);
- Inc(match_offset, (verbatim_bits shl 3));
- if READ_HUFFSYM(@pState^.AlignedTAble.Table[0], @pState^.AlignedTAble.Len[0],
- bits, inpos, i, j, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS,
- aligned_bits) <> 0 then
- begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- Inc(match_offset, aligned_bits);
- end
- else if (extra = 3) then begin
- //* aligned bits only */
- if READ_HUFFSYM(@pState^.AlignedTAble.Table[0], @pState^.AlignedTAble.Len[0],
- bits, inpos, i, j, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS,
- aligned_bits) <> 0 then
- begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- Inc(match_offset, aligned_bits);
- end
- else if (extra > 0) then begin //* extra==1, extra==2 */
- //* verbatim bits only */
- verbatim_bits := bits.read(extra, inpos);
- Inc(match_offset, verbatim_bits);
- end
- else begin //* extra == 0 */
- //* ??? */
- match_offset := 1;
- end;
- //* update repeated offset LRU queue */
- R2 := R1;
- R1 := R0;
- R0 := match_offset;
- end
- else if (match_offset = 0) then begin
- match_offset := R0;
- end
- else if (match_offset = 1) then begin
- match_offset := R1;
- R1 := R0;
- R0 := match_offset;
- end
- else begin //* match_offset == 2 */
- match_offset := R2;
- R2 := R0;
- R0 := match_offset;
- end;
- rundest := window + window_posn;
- runsrc := rundest - match_offset;
- Inc(window_posn, match_length);
- if (window_posn > window_size) then begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- Dec(this_run, match_length);
- //* copy any wrapped around source data */
- while ((runsrc < window) and (match_length > 0)) do begin
- Dec(match_length);
- rundest^ := (runsrc + window_size)^;
- Inc(rundest);
- Inc(runsrc);
- end;
- //* copy match data - no worries about destination wraps */
- while (match_length > 0) do begin
- Dec(match_length);
- rundest^ := runsrc^;
- Inc(rundest);
- Inc(runsrc);
- end;
- end;
- end;
- end;
- LZX_BLOCKTYPE_UNCOMPRESSED:
- begin
- if ((inpos + this_run) > endinp) then begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- Move(inpos^, (window + window_posn)^, this_run);
- Inc(inpos, this_run);
- Inc(window_posn, this_run);
- end;
- else
- Result := DECR_ILLEGALDATA; ///* might as well */
- bits.Free;
- Exit;
- end;
- this_run := pState^.block_remaining;
- end;
- end;
- if (togo <> 0) then begin
- Result := DECR_ILLEGALDATA;
- bits.Free;
- Exit;
- end;
- if window_posn = 0 then
- Move((window + window_size - outlen)^, outpos^, outlen)
- else
- Move((window + window_posn - outlen)^, outpos^, outlen);
- pState^.window_posn := window_posn;
- pState^.R0 := R0;
- pState^.R1 := R1;
- pState^.R2 := R2;
- //* intel E8 decoding */
- if ((pState^.frames_read < 32768) and (pState^.intel_filesize <> 0)) then begin
- if (outlen <= 6 or not pState^.intel_started) then begin
- Inc(pState^.intel_curpos, outlen);
- end
- else begin
- data := outpos;
- dataend := data + outlen - 10;
- curpos := pState^.intel_curpos;
- filesize := pState^.intel_filesize;
- pState^.intel_curpos := curpos + outlen;
- while (data < dataend) do begin
- if data^ <> $E8 then begin
- Inc(curpos);
- Inc(Data);
- continue;
- end;
- Inc(Data);
- abs_off := data[0] or (data[1]shl 8) or (data[2]shl 16) or (data[3]shl 24);
- if (abs_off >= curpos-1) and (abs_off < filesize) then begin
- if (abs_off >= 0) then
- rel_off := abs_off - curpos
- else
- rel_off := abs_off + filesize;
- {$IFDEF ENDIAN_BIG}
- PLongWord(data)^ := Swap(rel_off);
- {$ELSE}
- PLongword(data)^ := rel_off;
- {$ENDIF}
- end;
- Inc(data, 4);
- Inc(curpos, 5);
- end;
- end;
- end;
- Inc(pState^.frames_read);
- bits.Free;
- Result := DECR_OK;
- end;
- { TBufBits }
- procedure TBufBits.Init;
- begin
- bitsleft := 0;
- bitbuf := 0;
- end;
- procedure TBufBits.ensure(num: LongInt; var inpos:PByte);
- begin
- while (bitsleft < num) do begin
- bitbuf := bitbuf or (((inpos[1]shl 8) or inpos[0]) shl (ULONG_BITS-16 - bitsleft));
- Inc(bitsleft, 16);
- Inc(inpos, 2);
- end;
- end;
- function TBufBits.peek(numbits: LongInt): dword;
- begin
- Result := bitbuf shr (ULONG_BITS - numbits);
- end;
- function TBufBits.remove(numbits: LongInt): dword;
- begin
- bitbuf := bitbuf shl numbits;
- Result := bitbuf;
- Dec(bitsleft, numbits);
- end;
- function TBufBits.read(numbits: LongInt; var inpos: PByte): dword;
- begin
- ensure(numbits, inpos);
- Result := peek(numbits);
- remove(numbits);
- end;
- end.
|