paslzx.pas 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017
  1. { Copyright (C) <2005> <Andrew Haines> paslzx.pas
  2. This library is free software; you can redistribute it and/or modify it
  3. under the terms of the GNU Library General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or (at your
  5. option) any later version.
  6. This program is distributed in the hope that it will be useful, but WITHOUT
  7. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  8. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  9. for more details.
  10. You should have received a copy of the GNU Library General Public License
  11. along with this library; if not, write to the Free Software Foundation,
  12. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  13. }
  14. {
  15. See the file COPYING.LCL, included in this distribution,
  16. for details about the copyright.
  17. }
  18. {***************************************************************************
  19. * paslzx.pas - LZX decompression routines *
  20. * ------------------- *
  21. * *
  22. * maintainer: Andrew Haines <[email protected]> *
  23. * source: modified lzx.c from chmlib 0.37-4 *
  24. * notes: The lzx.c file was taken from cabextract v0.5, which was, *
  25. * itself, a modified version of the lzx decompression code *
  26. * from unlzx. This file would not be available without the *
  27. * invaluable help from Micha Nelissen fixing my errors. *
  28. * *
  29. * Licensed with permission of Stuart Caie with a modified *
  30. * LGPL. *
  31. * *
  32. * platforms: Should work on any platform that FreePascal is available *
  33. * on. However it has been tested on only an amd64(Linux) and *
  34. * x86(Linux and Windows). Only tested on little endian pc's. *
  35. ***************************************************************************}
  36. unit paslzx;
  37. {$mode objfpc}{$H+}{$R+}
  38. interface
  39. uses
  40. Classes, SysUtils;
  41. const
  42. DECR_OK = 0;
  43. DECR_DATAFORMAT = 1;
  44. DECR_ILLEGALDATA = 2;
  45. DECR_NOMEMORY = 3;
  46. // some constants defined by the LZX specification
  47. LZX_MIN_MATCH = 2;
  48. LZX_MAX_MATCH = 257;
  49. LZX_NUM_CHARS = 256;
  50. LZX_BLOCKTYPE_INVALID = 0; // also blocktypes 4-7 invalid
  51. LZX_BLOCKTYPE_VERBATIM = 1;
  52. LZX_BLOCKTYPE_ALIGNED = 2;
  53. LZX_BLOCKTYPE_UNCOMPRESSED= 3;
  54. LZX_PRETREE_NUM_ELEMENTS = 20;
  55. LZX_ALIGNED_NUM_ELEMENTS = 8; // aligned offset tree #elements
  56. LZX_NUM_PRIMARY_LENGTHS = 7; // this one missing from spec!
  57. LZX_NUM_SECONDARY_LENGTHS = 249;// length tree #elements
  58. // LZX huffman defines: tweak tablebits as desired
  59. LZX_PRETREE_MAXSYMBOLS = LZX_PRETREE_NUM_ELEMENTS;
  60. LZX_PRETREE_TABLEBITS = 6;
  61. LZX_MAINTREE_MAXSYMBOLS = LZX_NUM_CHARS + 50*8;
  62. LZX_MAINTREE_TABLEBITS = 12;
  63. LZX_LENGTH_MAXSYMBOLS = LZX_NUM_SECONDARY_LENGTHS+1;
  64. LZX_LENGTH_TABLEBITS = 12;
  65. LZX_ALIGNED_MAXSYMBOLS = LZX_ALIGNED_NUM_ELEMENTS;
  66. LZX_ALIGNED_TABLEBITS = 7;
  67. LZX_LENTABLE_SAFETY = 64; // we allow length table decoding overruns
  68. extra_bits: array [0..50] of Byte = (
  69. 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
  70. 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
  71. 15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
  72. 17, 17, 17
  73. );
  74. position_base: array [0..50] of dword = (
  75. 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
  76. 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
  77. 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
  78. 1835008, 1966080, 2097152
  79. );
  80. type
  81. { TBits }
  82. TBufBits = class
  83. private
  84. bitbuf: dword;
  85. bitsleft: LongInt;
  86. public
  87. procedure Init;
  88. procedure ensure(num: LongInt; var inpos:PByte);
  89. function peek(numbits: LongInt): dword;
  90. function remove(numbits: LongInt): dword;
  91. function read(numbits: LongInt; var inpos: PByte): dword;
  92. end;
  93. TLZX_PRETREE_TABLE = record
  94. Table: array [0..(1 shl LZX_PRETREE_TABLEBITS) + (LZX_PRETREE_MAXSYMBOLS shl 1)-1] of Word;
  95. Len: array [0..LZX_PRETREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY-1] of Byte;
  96. end;
  97. TLZX_MAINTREE_TABLE = record
  98. Table: array [0..(1 shl LZX_MAINTREE_TABLEBITS) + (LZX_MAINTREE_MAXSYMBOLS shl 1)-1] of Word;
  99. Len: array [0..LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY-1] of Byte;
  100. end;
  101. TLZX_LENGTH_TABLE = record
  102. Table: array [0..(1 shl LZX_LENGTH_TABLEBITS) + (LZX_LENGTH_MAXSYMBOLS shl 1)-1] of Word;
  103. Len: array [0..LZX_LENGTH_MAXSYMBOLS + LZX_LENTABLE_SAFETY-1] of Byte;
  104. end;
  105. TLZX_ALIGNED_TABLE = record
  106. Table: array [0..(1 shl LZX_ALIGNED_TABLEBITS) + (LZX_ALIGNED_MAXSYMBOLS shl 1)-1] of Word;
  107. Len: array [0..LZX_ALIGNED_MAXSYMBOLS + LZX_LENTABLE_SAFETY-1] of Byte;
  108. end;
  109. PLZXState = ^TLZXState;
  110. TLZXState = record
  111. window: PByte; // the actual decoding window
  112. window_size, // window size (32Kb through 2Mb)
  113. actual_size, // window size when it was first allocated
  114. window_posn, // current offset within the window
  115. R0, R1, R2: dword; // for the LRU offset system
  116. main_elements : Word; // number of main tree elements
  117. header_read: LongInt; // have we started decoding at all yet?
  118. block_type: Word; // type of this block
  119. block_length, // uncompressed length of this block
  120. block_remaining, // uncompressed bytes still left to decode
  121. frames_read: dword; // the number of CFDATA blocks
  122. intel_filesize, // magic header value used for transform
  123. intel_curpos: LongInt; // current offset in transform space
  124. intel_started: LongInt; // have we seen any translatable data yet?
  125. PreTreeTable: TLZX_PRETREE_TABLE;
  126. MainTreeTable: TLZX_MAINTREE_TABLE;
  127. LengthTable: TLZX_LENGTH_TABLE;
  128. AlignedTAble: TLZX_ALIGNED_TABLE;
  129. end;
  130. // create an lzx state object
  131. function LZXinit(window: LongInt): PLZXState;
  132. // destroy an lzx state object
  133. procedure LZXteardown(pState: PLZXState);
  134. // reset an lzx stream
  135. function LZXreset(pState: PLZXState): LongInt;
  136. function LZXdecompress(pState: PLZXstate; inpos, outpos: PByte; inlen, outlen: LongInt): LongInt;
  137. implementation
  138. const
  139. ULONG_BITS = sizeof(LongInt)shl 3;
  140. function make_decode_table(nsyms: dword; nbits: dword; length: PByte; table: PWord): LongInt;
  141. var
  142. Sym: Word;
  143. leaf: dword;
  144. bit_num: Byte = 1;
  145. fill: dword;
  146. pos: dword = 0; //* the current position in the decode table */
  147. table_mask: dword;
  148. bit_mask: dword; //* don't do 0 length codes */
  149. next_symbol: dword; //* base of allocation for long codes */
  150. begin
  151. Result := 0;
  152. table_mask := 1 shl nbits;
  153. bit_mask := table_mask shr 1;
  154. next_symbol := bit_mask;
  155. //* fill entries for codes short enough for a direct mapping */
  156. while (bit_num <= nbits) do begin
  157. for sym := 0 to nsyms-1 do begin
  158. if (length[sym] = bit_num) then begin
  159. leaf := pos;
  160. Inc(pos, bit_mask);
  161. if pos > table_mask then begin
  162. Result := 1; //* table overrun */
  163. exit;
  164. end;
  165. //* fill all possible lookups of this symbol with the symbol itself */
  166. fill := bit_mask;
  167. while fill > 0 do
  168. begin
  169. dec(fill);
  170. table[leaf] := sym;
  171. Inc(leaf);
  172. end;
  173. end;
  174. end;
  175. bit_mask := bit_mask shr 1;
  176. Inc(bit_num);
  177. end;
  178. //* if there are any codes longer than nbits */
  179. if pos <> table_mask then begin
  180. //* clear the remainder of the table */
  181. for sym := pos to table_mask-1 do table[sym] := 0;
  182. //* give ourselves room for codes to grow by up to 16 more bits */
  183. pos := pos shl 16;
  184. table_mask := table_mask shl 16;
  185. bit_mask := 1 shl 15;
  186. while (bit_num <= 16) do begin
  187. for sym := 0 to nsyms-1 do begin
  188. if (length[sym] = bit_num) then begin
  189. leaf := pos shr 16;
  190. for fill := 0 to (bit_num - nbits)-1 do begin
  191. //* if this path hasn't been taken yet, 'allocate' two entries */
  192. if (table[leaf] = 0) then begin
  193. table[(next_symbol shl 1)] := 0;
  194. table[(next_symbol shl 1)+1] := 0;
  195. table[leaf] := Word(next_symbol);
  196. Inc(next_symbol);
  197. end;
  198. //* follow the path and select either left or right for next bit */
  199. leaf := table[leaf] shl 1;
  200. if ((pos shr (15-fill)) and 1) > 0 then Inc(leaf);
  201. end;
  202. table[leaf] := sym;
  203. pos := pos + bit_mask;
  204. if (pos > table_mask) then begin
  205. Result := 1; //* table overflow */
  206. exit;
  207. end;
  208. end;
  209. end;
  210. bit_mask := bit_mask shr 1;
  211. Inc(bit_num);
  212. end;
  213. end;
  214. //* full table? */
  215. if (pos = table_mask) then begin
  216. Result := 0;
  217. Exit;
  218. end;
  219. //* either erroneous table, or all elements are 0 - let's find out. */
  220. for sym := 0 to nsyms-1 do begin
  221. if length[sym] > 0 then begin
  222. Result := 1;
  223. Exit;
  224. end;
  225. end;
  226. Result := 0;
  227. end;
  228. type
  229. PLZX_bits = ^TLzx_bits;
  230. Tlzx_bits = record
  231. bb: dword;
  232. bl: LongInt;
  233. ip: PByte;
  234. end;
  235. function READ_HUFFSYM(Table: PWord; Len: PByte; const bits: TBufBits; var inpos: PByte;
  236. var i, j: DWord; const TableBits, MaxSymbols: DWord; out z: LongInt): LongInt;
  237. var
  238. hufftbl: PWord;
  239. begin
  240. bits.ensure(16, inpos);
  241. hufftbl := Table;
  242. i := hufftbl[bits.peek(TableBits)];
  243. if (i) >= MaxSymbols then begin
  244. j := 1 shl (ULONG_BITS - TableBits);
  245. repeat
  246. j := j shr 1;
  247. i := i shl 1;
  248. i := i or ord((bits.bitbuf and j) <> 0);
  249. if j = 0 then begin
  250. Result := DECR_ILLEGALDATA;
  251. Exit;
  252. end;
  253. i := hufftbl[i];
  254. until i < MaxSymbols;
  255. end;
  256. z := i;
  257. j := Len[z];
  258. bits.remove(j);
  259. Result := 0;
  260. end;
  261. function lzx_read_lens(pState: PLZXState; lens: PByte; first: dword; last: dword; lb: Plzx_bits): LongInt;
  262. var
  263. i: dword = 0;
  264. j: dword = 0;
  265. x,y: dword;
  266. z: LongInt;
  267. inpos: PByte;
  268. bits: TBufBits;
  269. begin
  270. bits := TBufBits.Create;
  271. bits.bitbuf := lb^.bb;
  272. bits.bitsleft := lb^.bl;
  273. inpos := lb^.ip;
  274. for X := 0 to 19 do begin
  275. y := bits.read(4, inpos);
  276. pState^.PreTreeTable.Len[x] := byte(y);
  277. end;
  278. if make_decode_table(LZX_PRETREE_MAXSYMBOLS, LZX_PRETREE_TABLEBITS,
  279. @pState^.PreTreeTable.Len[0],@pState^.PreTreeTable.Table[0]) >0 then
  280. begin
  281. Result := DECR_ILLEGALDATA;
  282. bits.Free;
  283. Exit;
  284. end;
  285. x := first;
  286. while x < last do begin
  287. if READ_HUFFSYM(@pState^.PreTreeTable.Table[0], @pstate^.PreTreeTable.Len[0], bits, inpos, i, j,
  288. LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, z) <> 0 then
  289. begin
  290. Result := DECR_ILLEGALDATA;
  291. bits.Free;
  292. Exit;
  293. end;
  294. if (z = 17) then begin
  295. y := bits.read(4, inpos);
  296. Inc(y, 4);
  297. while y > 0 do begin
  298. dec(y);
  299. Lens[x] := 0;
  300. Inc(x);
  301. end;
  302. end
  303. else if (z = 18) then begin
  304. y := bits.read(5, inpos);
  305. Inc(y, 20);
  306. while y > 0 do begin
  307. dec(y);
  308. lens[x] := 0;
  309. inc(x);
  310. end;
  311. end
  312. else if (z = 19) then begin
  313. y := bits.read(1, inpos);
  314. Inc(y, 4);
  315. if READ_HUFFSYM(@pState^.PreTreeTable.Table[0], @pstate^.PreTreeTable.Len[0], bits, inpos, i, j,
  316. LZX_PRETREE_TABLEBITS, LZX_PRETREE_MAXSYMBOLS, z) <> 0 then
  317. begin
  318. Result := DECR_ILLEGALDATA;
  319. bits.Free;
  320. Exit;
  321. end;
  322. z := lens[x] - z;
  323. if (z < 0) then z := z + 17;
  324. while y > 0 do begin
  325. dec(y);
  326. lens[x] := byte(z);
  327. inc(x);
  328. end;
  329. end
  330. else begin
  331. z := lens[x] - z;
  332. if (z < 0) then z := z + 17;
  333. lens[x] := byte(z);
  334. inc(x);
  335. end;
  336. end;
  337. lb^.bb := bits.bitbuf;
  338. lb^.bl := bits.bitsleft;
  339. lb^.ip := inpos;
  340. Result := 0;
  341. bits.Free;
  342. end;
  343. //////////////////////////////////////////////////////////////////////////////////////
  344. function LZXinit(window: LongInt): PLZXState;
  345. var
  346. pState: PLZXState;
  347. wndsize: dword;
  348. i,
  349. posn_slots: LongInt;
  350. begin
  351. Result := nil;
  352. wndsize := 1 shl window;
  353. //* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
  354. //* if a previously allocated window is big enough, keep it */
  355. if (window < 15) or (window > 21) then begin
  356. Exit;
  357. end;
  358. //* allocate state and associated window */
  359. New(pState);
  360. pState^.window := GetMem(wndsize);
  361. if pState^.window = nil then
  362. begin
  363. Dispose(pState);
  364. Result := nil;
  365. exit;
  366. end;
  367. pState^.actual_size := wndsize;
  368. pState^.window_size := wndsize;
  369. //* calculate required position slots */
  370. if (window = 20) then posn_slots := 42
  371. else if (window = 21) then posn_slots := 50
  372. else posn_slots := window shl 1;
  373. ///** alternatively **/
  374. ///* posn_slots=i=0; while (i < wndsize) i += 1 << extra_bits[posn_slots++]; */
  375. ///* initialize other state */
  376. pState^.R0 := 1;
  377. pState^.R1 := 1;
  378. pState^.R2 := 1;
  379. pState^.main_elements := LZX_NUM_CHARS + (posn_slots shl 3);
  380. pState^.header_read := 0;
  381. pState^.frames_read := 0;
  382. pState^.block_remaining := 0;
  383. pState^.block_type := LZX_BLOCKTYPE_INVALID;
  384. pState^.intel_curpos := 0;
  385. pState^.intel_started := 0;
  386. pState^.window_posn := 0;
  387. ///* initialise tables to 0 (because deltas will be applied to them) */
  388. for i := 0 to LZX_MAINTREE_MAXSYMBOLS-1 do pState^.MainTreeTable.Len[i] := 0;
  389. for i := 0 to LZX_LENGTH_MAXSYMBOLS-1 do pState^.LengthTable.Len[i] := 0;
  390. Result := pState;
  391. end;
  392. procedure LZXteardown(pState: PLZXState);
  393. begin
  394. if pState <> nil then
  395. begin
  396. if pState^.window <> nil then
  397. Freemem(pState^.window);
  398. Dispose(pState);
  399. end;
  400. end;
  401. function LZXreset(pState: PLZXState): LongInt;
  402. var
  403. i: LongInt;
  404. begin
  405. pState^.R0 := 1;
  406. pState^.R1 := 1;
  407. pState^.R2 := 1;
  408. pState^.header_read := 0;
  409. pState^.frames_read := 0;
  410. pState^.block_remaining := 0;
  411. pState^.block_type := LZX_BLOCKTYPE_INVALID;
  412. pState^.intel_curpos := 0;
  413. pState^.intel_started := 0;
  414. pState^.window_posn := 0;
  415. for i := 0 to (LZX_MAINTREE_MAXSYMBOLS + LZX_LENTABLE_SAFETY - 1) do pState^.MainTreeTable.Len[i] := 0;
  416. for i := 0 to LZX_LENGTH_MAXSYMBOLS+LZX_LENTABLE_SAFETY-1 do pState^.LengthTable.Len[i] := 0;
  417. Result := DECR_OK;
  418. end;
  419. function LZXdecompress(pState: PLZXstate; inpos, outpos: PByte; inlen,
  420. outlen: LongInt): LongInt;
  421. var
  422. endinp: PByte;
  423. window: PByte;
  424. runsrc,
  425. rundest: PByte;
  426. window_posn: dword;
  427. window_size: dword;
  428. R0,
  429. r1,
  430. R2: dword;
  431. bits: TBufBits;
  432. match_offset,
  433. i,j,k : dword;
  434. lb: tlzx_bits;
  435. togo,
  436. this_run,
  437. main_element,
  438. aligned_bits: LongInt;
  439. match_length,
  440. length_footer,
  441. extra,
  442. verbatim_bits: LongInt;
  443. data,
  444. dataend: PByte;
  445. curpos,
  446. filesize,
  447. abs_off,
  448. rel_off: LongInt;
  449. function READ_LENGTHS(Len: PByte; first: dword; last: dword): Longint;
  450. begin
  451. Result := 0;
  452. lb.bb := bits.bitbuf;
  453. lb.bl := bits.bitsleft;
  454. lb.ip := inpos;
  455. if (lzx_read_lens(pState, Len,first,last,@lb)) > 0 then begin
  456. Result := DECR_ILLEGALDATA;
  457. Exit;
  458. end;
  459. bits.bitbuf := lb.bb;
  460. bits.bitsleft := lb.bl;
  461. inpos := lb.ip;
  462. end;
  463. procedure HandleBlockTypeAligned;
  464. var
  465. i, j: dword;
  466. begin
  467. for i := 0 to 7 do begin
  468. j:= bits.read(3, inpos);
  469. pState^.AlignedTAble.Len[i] := Word(j);
  470. end;
  471. if make_decode_table(LZX_ALIGNED_MAXSYMBOLS, LZX_ALIGNED_TABLEBITS,
  472. @pState^.AlignedTAble.Len[0],@pState^.AlignedTAble.Table[0]) >0 then
  473. begin
  474. Result := DECR_ILLEGALDATA;
  475. Exit;
  476. end;
  477. end;
  478. procedure HandleBlockTypeVerbatim;
  479. begin
  480. if (
  481. READ_LENGTHS(@pState^.MainTreeTable.Len[0], 0, 256) = DECR_ILLEGALDATA)
  482. or (
  483. READ_LENGTHS(@pState^.MainTreeTable.Len[0], 256, pState^.main_elements) = DECR_ILLEGALDATA)
  484. then begin
  485. Result := DECR_ILLEGALDATA;
  486. Exit;
  487. end;
  488. if make_decode_table(LZX_MAINTREE_MAXSYMBOLS, LZX_MAINTREE_TABLEBITS,
  489. @pState^.MainTreeTable.Len[0], @pState^.MainTreeTable.Table[0]) >0 then
  490. begin
  491. Result := DECR_ILLEGALDATA;
  492. Exit;
  493. end;
  494. if pState^.MainTreeTable.Len[$E8] <> 0 then
  495. pState^.intel_started := 1;
  496. if READ_LENGTHS(@pState^.LengthTable.Len[0], 0, LZX_NUM_SECONDARY_LENGTHS) = DECR_ILLEGALDATA then begin
  497. Result := DECR_ILLEGALDATA;
  498. Exit;
  499. end;
  500. if make_decode_table(LZX_LENGTH_MAXSYMBOLS, LZX_LENGTH_TABLEBITS,
  501. @pState^.LengthTable.Len[0],@pState^.LengthTable.Table[0]) >0 then
  502. begin
  503. Result := DECR_ILLEGALDATA;
  504. Exit;
  505. end;
  506. end;
  507. begin
  508. endinp := inpos + inlen;
  509. window := pState^.window;
  510. window_posn := pState^.window_posn;
  511. window_size := pState^.window_size;
  512. R0 := pState^.R0;
  513. R1 := pState^.R1;
  514. R2 := pState^.R2;
  515. togo := outlen;//, this_run, main_element, aligned_bits;
  516. bits := TBufBits.Create;
  517. bits.Init;
  518. //* read header if necessary */
  519. if (pState^.header_read) = 0 then begin
  520. i := 0;
  521. j := 0;
  522. k := bits.read(1, inpos);
  523. if (k) > 0 then begin
  524. i := bits.read(16, inpos);
  525. j := bits.read(16, inpos);
  526. end;
  527. pState^.intel_filesize := (i shl 16) or j; ///* or 0 if not encoded */
  528. pState^.header_read := 1;
  529. end;
  530. ///* main decoding loop */
  531. while (togo > 0) do begin
  532. ///* last block finished, new block expected */
  533. if (pState^.block_remaining = 0) then begin
  534. if (pState^.block_type = LZX_BLOCKTYPE_UNCOMPRESSED) then begin
  535. if (pState^.block_length and 1) > 0 then Inc(inpos); //* realign bitstream to word */
  536. bits.Init;
  537. end;
  538. pState^.block_type := Word(bits.read(3, inpos));
  539. i := bits.read(16, inpos);
  540. j := bits.read(8, inpos);
  541. pState^.block_length := (i shl 8) or j;
  542. pState^.block_remaining := pState^.block_length;
  543. case (pState^.block_type) of
  544. LZX_BLOCKTYPE_ALIGNED:
  545. begin
  546. HandleBlockTypeAligned;
  547. //* rest of aligned header is same as verbatim */
  548. HandleBlockTypeVerbatim;
  549. end;
  550. LZX_BLOCKTYPE_VERBATIM:
  551. begin
  552. HandleBlockTypeVerbatim;
  553. end;
  554. LZX_BLOCKTYPE_UNCOMPRESSED:
  555. begin
  556. pState^.intel_started := 1; //* because we can't assume otherwise */
  557. bits.ensure(16, inpos); //* get up to 16 pad bits into the buffer */
  558. if (bits.bitsleft > 16) then Dec(inpos ,2); //* and align the bitstream! */
  559. R0 := inpos[0] or (inpos[1]shl 8)or(inpos[2]shl 16)or(inpos[3]shl 24);
  560. Inc(inpos,4);
  561. R1 := inpos[0] or (inpos[1]shl 8)or(inpos[2]shl 16)or(inpos[3]shl 24);
  562. Inc(inpos,4);
  563. R2 := inpos[0] or (inpos[1]shl 8)or(inpos[2]shl 16)or(inpos[3]shl 24);
  564. Inc(inpos,4);
  565. end;
  566. else
  567. Result := DECR_ILLEGALDATA;
  568. bits.Free;
  569. Exit;
  570. end;
  571. end;
  572. //* buffer exhaustion check */
  573. if (inpos > endinp) then begin
  574. {* it's possible to have a file where the next run is less than
  575. * 16 bits in size. In this case, the READ_HUFFSYM() macro used
  576. * in building the tables will exhaust the buffer, so we should
  577. * allow for this, but not allow those accidentally read bits to
  578. * be used (so we check that there are at least 16 bits
  579. * remaining - in this boundary case they aren't really part of
  580. * the compressed data)
  581. *}
  582. if (inpos > (endinp+2)) or (bits.bitsleft < 16) then begin
  583. Result := DECR_ILLEGALDATA;
  584. bits.Free;
  585. Exit;
  586. end;
  587. end;
  588. this_run := pState^.block_remaining;
  589. while (this_run > 0) and (togo > 0) do begin
  590. if (this_run > togo) then this_run := togo;
  591. Dec(togo, this_run);
  592. Dec(pState^.block_remaining, this_run);
  593. //* apply 2^x-1 mask */
  594. window_posn := window_posn and (window_size - 1);
  595. //* runs can't straddle the window wraparound */
  596. if ((window_posn + this_run) > window_size) then begin
  597. Result := DECR_DATAFORMAT;
  598. bits.Free;
  599. Exit;
  600. end;
  601. case (pState^.block_type) of
  602. LZX_BLOCKTYPE_VERBATIM:
  603. begin
  604. while (this_run > 0) do begin
  605. if READ_HUFFSYM(@pState^.MainTreeTable.Table[0], @pState^.MainTreeTable.Len[0],
  606. bits, inpos, i, j, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS,
  607. main_element) <> 0 then
  608. begin
  609. Result := DECR_ILLEGALDATA;
  610. bits.Free;
  611. Exit;
  612. end;
  613. if (main_element < LZX_NUM_CHARS) then begin
  614. //* literal: 0 to LZX_NUM_CHARS-1 */
  615. window[window_posn] := Byte(main_element);
  616. Inc(window_posn);
  617. Dec(this_run);
  618. end
  619. else begin
  620. //* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
  621. Dec(main_element, LZX_NUM_CHARS);
  622. match_length := main_element and LZX_NUM_PRIMARY_LENGTHS;
  623. if (match_length = LZX_NUM_PRIMARY_LENGTHS) then begin
  624. if READ_HUFFSYM(@pState^.LengthTable.Table[0], @pState^.LengthTable.Len[0],
  625. bits, inpos, i, j, LZX_LENGTH_TABLEBITS, LZX_LENGTH_MAXSYMBOLS,
  626. length_footer) <> 0 then
  627. begin
  628. Result := DECR_ILLEGALDATA;
  629. bits.Free;
  630. Exit;
  631. end;
  632. Inc(match_length, length_footer);
  633. end;
  634. Inc(match_length, LZX_MIN_MATCH);
  635. match_offset := main_element shr 3;
  636. if (match_offset > 2) then begin
  637. //* not repeated offset */
  638. if (match_offset <> 3) then begin
  639. extra := extra_bits[match_offset];
  640. verbatim_bits := bits.read(extra, inpos);
  641. match_offset := position_base[match_offset] - 2 + verbatim_bits;
  642. end
  643. else begin
  644. match_offset := 1;
  645. end;
  646. //* update repeated offset LRU queue */
  647. R2 := R1;
  648. R1 := R0;
  649. R0 := match_offset;
  650. end
  651. else if (match_offset = 0) then begin
  652. match_offset := R0;
  653. end
  654. else if (match_offset = 1) then begin
  655. match_offset := R1;
  656. R1 := R0;
  657. R0 := match_offset;
  658. end
  659. else begin //* match_offset == 2 */
  660. match_offset := R2;
  661. R2 := R0;
  662. R0 := match_offset;
  663. end;
  664. rundest := window + window_posn;
  665. runsrc := rundest - match_offset;
  666. Inc(window_posn, match_length);
  667. if (window_posn > window_size) then begin
  668. Result := DECR_ILLEGALDATA;
  669. bits.Free;
  670. Exit;
  671. end;
  672. Dec(this_run, match_length);
  673. ///* copy any wrapped around source data */
  674. while ((runsrc < window) and (match_length > 0)) do begin
  675. Dec(match_length);
  676. rundest^ := (runsrc + window_size)^;
  677. Inc(rundest);
  678. Inc(runsrc);
  679. end;
  680. //* copy match data - no worries about destination wraps */
  681. while (match_length > 0) do begin
  682. Dec(match_length);
  683. rundest^ := runsrc^;
  684. Inc(rundest);
  685. Inc(runsrc);
  686. end;
  687. end
  688. end;
  689. end;
  690. LZX_BLOCKTYPE_ALIGNED:
  691. begin
  692. while (this_run > 0) do begin
  693. if READ_HUFFSYM(@pState^.MainTreeTable.Table[0], @pState^.MainTreeTable.Len[0], bits,
  694. inpos, i, j, LZX_MAINTREE_TABLEBITS, LZX_MAINTREE_MAXSYMBOLS, main_element) <> 0 then
  695. begin
  696. Result := DECR_ILLEGALDATA;
  697. bits.Free;
  698. Exit;
  699. end;
  700. if (main_element < LZX_NUM_CHARS) then begin
  701. //* literal: 0 to LZX_NUM_CHARS-1 */
  702. window[window_posn] := Byte(main_element);
  703. Inc(window_posn);
  704. Dec(this_run);
  705. end
  706. else begin
  707. //* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
  708. Dec(main_element, LZX_NUM_CHARS);
  709. match_length := main_element and LZX_NUM_PRIMARY_LENGTHS;
  710. if (match_length = LZX_NUM_PRIMARY_LENGTHS) then begin
  711. if READ_HUFFSYM(@pState^.LengthTable.Table[0], @pState^.LengthTable.Len[0],
  712. bits, inpos, i, j, LZX_LENGTH_TABLEBITS,
  713. LZX_LENGTH_MAXSYMBOLS, length_footer) <> 0 then
  714. begin
  715. Result := DECR_ILLEGALDATA;
  716. bits.Free;
  717. Exit;
  718. end;
  719. Inc(match_length, length_footer);
  720. end;
  721. Inc(match_length, LZX_MIN_MATCH);
  722. match_offset := main_element shr 3;
  723. if (match_offset > 2) then begin
  724. //* not repeated offset */
  725. extra := extra_bits[match_offset];
  726. match_offset := position_base[match_offset] - 2;
  727. if (extra > 3) then begin
  728. //* verbatim and aligned bits */
  729. Dec(extra, 3);
  730. verbatim_bits := bits.read(extra, inpos);
  731. Inc(match_offset, (verbatim_bits shl 3));
  732. if READ_HUFFSYM(@pState^.AlignedTAble.Table[0], @pState^.AlignedTAble.Len[0],
  733. bits, inpos, i, j, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS,
  734. aligned_bits) <> 0 then
  735. begin
  736. Result := DECR_ILLEGALDATA;
  737. bits.Free;
  738. Exit;
  739. end;
  740. Inc(match_offset, aligned_bits);
  741. end
  742. else if (extra = 3) then begin
  743. //* aligned bits only */
  744. if READ_HUFFSYM(@pState^.AlignedTAble.Table[0], @pState^.AlignedTAble.Len[0],
  745. bits, inpos, i, j, LZX_ALIGNED_TABLEBITS, LZX_ALIGNED_MAXSYMBOLS,
  746. aligned_bits) <> 0 then
  747. begin
  748. Result := DECR_ILLEGALDATA;
  749. bits.Free;
  750. Exit;
  751. end;
  752. Inc(match_offset, aligned_bits);
  753. end
  754. else if (extra > 0) then begin //* extra==1, extra==2 */
  755. //* verbatim bits only */
  756. verbatim_bits := bits.read(extra, inpos);
  757. Inc(match_offset, verbatim_bits);
  758. end
  759. else begin //* extra == 0 */
  760. //* ??? */
  761. match_offset := 1;
  762. end;
  763. //* update repeated offset LRU queue */
  764. R2 := R1;
  765. R1 := R0;
  766. R0 := match_offset;
  767. end
  768. else if (match_offset = 0) then begin
  769. match_offset := R0;
  770. end
  771. else if (match_offset = 1) then begin
  772. match_offset := R1;
  773. R1 := R0;
  774. R0 := match_offset;
  775. end
  776. else begin //* match_offset == 2 */
  777. match_offset := R2;
  778. R2 := R0;
  779. R0 := match_offset;
  780. end;
  781. rundest := window + window_posn;
  782. runsrc := rundest - match_offset;
  783. Inc(window_posn, match_length);
  784. if (window_posn > window_size) then begin
  785. Result := DECR_ILLEGALDATA;
  786. bits.Free;
  787. Exit;
  788. end;
  789. Dec(this_run, match_length);
  790. //* copy any wrapped around source data */
  791. while ((runsrc < window) and (match_length > 0)) do begin
  792. Dec(match_length);
  793. rundest^ := (runsrc + window_size)^;
  794. Inc(rundest);
  795. Inc(runsrc);
  796. end;
  797. //* copy match data - no worries about destination wraps */
  798. while (match_length > 0) do begin
  799. Dec(match_length);
  800. rundest^ := runsrc^;
  801. Inc(rundest);
  802. Inc(runsrc);
  803. end;
  804. end;
  805. end;
  806. end;
  807. LZX_BLOCKTYPE_UNCOMPRESSED:
  808. begin
  809. if ((inpos + this_run) > endinp) then begin
  810. Result := DECR_ILLEGALDATA;
  811. bits.Free;
  812. Exit;
  813. end;
  814. Move(inpos^, (window + window_posn)^, this_run);
  815. Inc(inpos, this_run);
  816. Inc(window_posn, this_run);
  817. end;
  818. else
  819. Result := DECR_ILLEGALDATA; ///* might as well */
  820. bits.Free;
  821. Exit;
  822. end;
  823. this_run := pState^.block_remaining;
  824. end;
  825. end;
  826. if (togo <> 0) then begin
  827. Result := DECR_ILLEGALDATA;
  828. bits.Free;
  829. Exit;
  830. end;
  831. if window_posn = 0 then
  832. Move((window + window_size - outlen)^, outpos^, outlen)
  833. else
  834. Move((window + window_posn - outlen)^, outpos^, outlen);
  835. pState^.window_posn := window_posn;
  836. pState^.R0 := R0;
  837. pState^.R1 := R1;
  838. pState^.R2 := R2;
  839. //* intel E8 decoding */
  840. if ((pState^.frames_read < 32768) and (pState^.intel_filesize <> 0)) then begin
  841. if (outlen <= 6 or not pState^.intel_started) then begin
  842. Inc(pState^.intel_curpos, outlen);
  843. end
  844. else begin
  845. data := outpos;
  846. dataend := data + outlen - 10;
  847. curpos := pState^.intel_curpos;
  848. filesize := pState^.intel_filesize;
  849. pState^.intel_curpos := curpos + outlen;
  850. while (data < dataend) do begin
  851. if data^ <> $E8 then begin
  852. Inc(curpos);
  853. Inc(Data);
  854. continue;
  855. end;
  856. Inc(Data);
  857. abs_off := data[0] or (data[1]shl 8) or (data[2]shl 16) or (data[3]shl 24);
  858. if (abs_off >= curpos-1) and (abs_off < filesize) then begin
  859. if (abs_off >= 0) then
  860. rel_off := abs_off - curpos
  861. else
  862. rel_off := abs_off + filesize;
  863. {$IFDEF ENDIAN_BIG}
  864. PLongWord(data)^ := Swap(rel_off);
  865. {$ELSE}
  866. PLongword(data)^ := rel_off;
  867. {$ENDIF}
  868. end;
  869. Inc(data, 4);
  870. Inc(curpos, 5);
  871. end;
  872. end;
  873. end;
  874. Inc(pState^.frames_read);
  875. bits.Free;
  876. Result := DECR_OK;
  877. end;
  878. { TBufBits }
  879. procedure TBufBits.Init;
  880. begin
  881. bitsleft := 0;
  882. bitbuf := 0;
  883. end;
  884. procedure TBufBits.ensure(num: LongInt; var inpos:PByte);
  885. begin
  886. while (bitsleft < num) do begin
  887. bitbuf := bitbuf or (((inpos[1]shl 8) or inpos[0]) shl (ULONG_BITS-16 - bitsleft));
  888. Inc(bitsleft, 16);
  889. Inc(inpos, 2);
  890. end;
  891. end;
  892. function TBufBits.peek(numbits: LongInt): dword;
  893. begin
  894. Result := bitbuf shr (ULONG_BITS - numbits);
  895. end;
  896. function TBufBits.remove(numbits: LongInt): dword;
  897. begin
  898. bitbuf := bitbuf shl numbits;
  899. Result := bitbuf;
  900. Dec(bitsleft, numbits);
  901. end;
  902. function TBufBits.read(numbits: LongInt; var inpos: PByte): dword;
  903. begin
  904. ensure(numbits, inpos);
  905. Result := peek(numbits);
  906. remove(numbits);
  907. end;
  908. end.