paslzxcomp.pas 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  1. { Copyright (C) <2005> <Andrew Haines> paslzxcomp.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.FPC, included in this distribution,
  16. for details about the copyright.
  17. }
  18. unit paslzxcomp;
  19. {$MODE OBJFPC}
  20. {$GOTO ON}
  21. interface
  22. uses paslznonslide;
  23. const
  24. MIN_MATCH = 2;
  25. MAX_MATCH = 257;
  26. NUM_CHARS = 256;
  27. NUM_PRIMARY_LENGTHS = 7;
  28. NUM_SECONDARY_LENGTHS = 249;
  29. { the names of these constants are specific to this library }
  30. LZX_MAX_CODE_LENGTH = 16;
  31. LZX_FRAME_SIZE = 32768;
  32. LZX_PRETREE_SIZE = 20;
  33. LZX_ALIGNED_BITS = 3;
  34. LZX_ALIGNED_SIZE = 8;
  35. LZX_VERBATIM_BLOCK = 1;
  36. LZX_ALIGNED_OFFSET_BLOCK = 2;
  37. {$IFDEF FPC}
  38. {$PACKRECORDS C}
  39. {$ENDIF}
  40. {
  41. File lzx_compress.h, part of lzxcomp library
  42. Copyright (C) 2002 Matthew T. Russotto
  43. This program is free software; you can redistribute it and/or modify
  44. it under the terms of the GNU Lesser General Public License as published by
  45. the Free Software Foundation; version 2.1 only
  46. This program is distributed in the hope that it will be useful,
  47. but WITHOUT ANY WARRANTY; without even the implied warranty of
  48. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  49. GNU Lesser General Public License for more details.
  50. You should have received a copy of the GNU Lesser General Public License
  51. along with this program; if not, write to the Free Software
  52. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  53. }
  54. type
  55. PPlzx_data = ^Plzx_data;
  56. Plzx_data = ^lzx_data;
  57. TGetBytesFunc = function (arg:pointer; n:longint; buf:pointer):longint; cdecl;
  58. TWriteBytesFunc = function (arg:pointer; n:longint; buf:pointer):longint; cdecl;
  59. TMarkFrameFunc = procedure (arg:pointer; uncomp:dword; comp:dword); cdecl;
  60. TIsEndOfFileFunc = function (arg:pointer): longbool; cdecl;
  61. { add more here? Error codes, # blocks, # frames, etc? }
  62. lzx_results = record
  63. len_compressed_output : longint;
  64. len_uncompressed_input : longint;
  65. end;
  66. phuff_entry = ^huff_entry;
  67. huff_entry = record
  68. codelength: smallint;
  69. code: word;
  70. end;
  71. lzx_data = record
  72. in_arg : pointer;
  73. out_arg: pointer;
  74. mark_frame_arg: pointer;
  75. get_bytes: TGetBytesFunc;
  76. at_eof: TIsEndOfFileFunc;
  77. put_bytes: TWriteBytesFunc;
  78. mark_frame: TMarkFrameFunc;
  79. lzi: plz_info;
  80. {/* a 'frame' is an 0x8000 byte thing. Called that because otherwise
  81. I'd confuse myself overloading 'block' */}
  82. left_in_frame: longint;
  83. left_in_block: longint;
  84. R0, R1, R2: longint;
  85. num_position_slots: longint;
  86. //* this is the LZX block size */
  87. block_size: longint;
  88. main_freq_table: plongint;
  89. length_freq_table: array [0..NUM_SECONDARY_LENGTHS-1] of longint;
  90. aligned_freq_table: array [0..LZX_ALIGNED_SIZE-1] of longint;
  91. block_codes: plongword;
  92. block_codesp: plongword;
  93. main_tree: phuff_entry;
  94. length_tree: array[0..NUM_SECONDARY_LENGTHS-1] of huff_entry;
  95. aligned_tree: array[0..LZX_ALIGNED_SIZE-1] of huff_entry;
  96. main_tree_size: longint;
  97. bit_buf: word;
  98. bits_in_buf: longint;
  99. main_entropy: double;
  100. last_ratio: double;
  101. prev_main_treelengths: pbyte;
  102. prev_length_treelengths: array [0..NUM_SECONDARY_LENGTHS-1] of byte;
  103. len_uncompressed_input: longword;
  104. len_compressed_output: longword;
  105. need_1bit_header: smallint;
  106. subdivide: smallint; //* 0 = don't subdivide, 1 = allowed, -1 = requested */
  107. end;
  108. Plzx_results = ^lzx_results;
  109. function lzx_init(lzxdp:Pplzx_data; wsize_code:longint; get_bytes:TGetBytesFunc; get_bytes_arg:pointer; at_eof:TIsEndOfFileFunc;
  110. put_bytes:TWriteBytesFunc; put_bytes_arg:pointer; mark_frame:TMarkFrameFunc; mark_frame_arg:pointer):longint;
  111. procedure lzx_reset(lzxd:plzx_data);
  112. function lzx_compress_block(lzxd:plzx_data; block_size:longint; subdivide: LongBool):longint;
  113. function lzx_finish(lzxd:plzx_data; lzxr:plzx_results):longint;
  114. implementation
  115. uses math, sysutils;
  116. var
  117. rloge2: double; // set in initialization section
  118. const
  119. num_position_slots: array [0..6] of smallint = (30, 32, 34, 36, 38, 42, 50);
  120. extra_bits: array [0..50] of Byte = (
  121. 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
  122. 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14,
  123. 15, 15, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
  124. 17, 17, 17
  125. );
  126. position_base: array [0..50] of dword = (
  127. 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
  128. 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152,
  129. 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
  130. 1835008, 1966080, 2097152
  131. );
  132. type
  133. pih_elem = ^ih_elem;
  134. ih_elem = record
  135. freq: longint;
  136. sym: smallint;
  137. pathlength: smallint;
  138. parent: pih_elem;
  139. left: pih_elem;
  140. right: pih_elem;
  141. end;
  142. ph_elem = ^h_elem;
  143. h_elem = record
  144. freq: longint;
  145. sym: smallint;
  146. pathlength: smallint;
  147. parent: pih_elem;
  148. code: word;
  149. end;
  150. function cmp_leaves(const in_a: ph_elem; const in_b: ph_elem): longint;
  151. begin
  152. if (in_a^.freq = 0) and (in_b^.freq <> 0) then
  153. Exit(1);
  154. if (in_a^.freq <> 0) and (in_b^.freq = 0) then
  155. Exit(-1);
  156. if (in_a^.freq = in_b^.freq) then
  157. Exit(in_a^.sym - in_b^.sym);
  158. Exit(in_a^.freq - in_b^.freq);
  159. end;
  160. function cmp_pathlengths(const in_a: ph_elem; const in_b: ph_elem): longint;
  161. begin
  162. if (in_a^.pathlength = in_b^.pathlength) then
  163. //* see note on canonical pathlengths */
  164. Exit(in_b^.sym - in_a^.sym);
  165. Exit(in_b^.pathlength - in_a^.pathlength);
  166. end;
  167. type
  168. TQSortCompFunc = function(const in_a: ph_elem; const in_b: ph_elem): longint;
  169. procedure qsort(a_array: ph_elem; nelem: integer; cmpfunc: TQSortCompFunc);
  170. var
  171. tmp: h_elem;
  172. procedure QuickSort(L, R: Integer);
  173. var
  174. I, J, Pivot: Integer;
  175. begin
  176. repeat
  177. I := L;
  178. J := R;
  179. Pivot := (L + R) div 2;
  180. repeat
  181. while cmpfunc(@a_array[I], @a_array[Pivot]) < 0 do Inc(I);
  182. while cmpfunc(@a_array[J], @a_array[Pivot]) > 0 do Dec(J);
  183. if I <= J then
  184. begin
  185. // exchange I and J
  186. tmp := a_array[I];
  187. a_array[I] := a_array[J];
  188. a_array[J] := tmp;
  189. if Pivot = I then
  190. Pivot := J
  191. else if Pivot = J then
  192. Pivot := I;
  193. Inc(I);
  194. Dec(j);
  195. end;
  196. until I > J;
  197. if L < J then
  198. QuickSort(L,J);
  199. L := I;
  200. until I >= R;
  201. end;
  202. begin
  203. QuickSort(0, nelem - 1);
  204. end;
  205. procedure build_huffman_tree(nelem: longint; max_code_length: longint; freq: plongint; tree: phuff_entry);
  206. var
  207. leaves: ph_elem;
  208. inodes: pih_elem;
  209. next_inode: pih_elem;
  210. cur_inode: pih_elem;
  211. cur_leaf :ph_elem;
  212. leaves_left,
  213. nleaves,
  214. pathlength: longint;
  215. cur_code: word;
  216. codes_too_long: smallint = 0;
  217. f1, f2: pih_elem;
  218. i: longint;
  219. begin
  220. leaves := GetMem(nelem * sizeof(h_elem));
  221. for i := 0 to nelem-1 do begin
  222. leaves[i].freq := freq[i];
  223. leaves[i].sym := i;
  224. leaves[i].pathlength := 0;
  225. end;
  226. qsort(leaves, nelem, @cmp_leaves);
  227. leaves_left := 0;
  228. while leaves_left < nelem do begin
  229. if (leaves[leaves_left].freq) = 0 then break;
  230. Inc(leaves_left);
  231. end;
  232. nleaves := leaves_left;
  233. if (nleaves >= 2) then begin
  234. inodes := AllocMem((nelem-1) * sizeof(ih_elem));
  235. repeat
  236. if (codes_too_long <> 0) then begin
  237. leaves_left := 0;
  238. while leaves_left < nelem do begin
  239. if (leaves[leaves_left].freq = 0) then break;
  240. if (leaves[leaves_left].freq <> 1) then begin
  241. leaves[leaves_left].freq := leaves[leaves_left].freq shr 1;
  242. codes_too_long := 0;
  243. Inc(leaves_left);
  244. end;
  245. end;
  246. if codes_too_long <> 0 then
  247. raise Exception.Create('!codes_too_long');
  248. end;
  249. cur_leaf := leaves;
  250. cur_inode := inodes;
  251. next_inode := cur_inode;
  252. repeat
  253. f1 := nil;
  254. f2 := nil;
  255. if (leaves_left <> 0) and
  256. ((cur_inode = next_inode) or
  257. (cur_leaf^.freq <= cur_inode^.freq)) then begin
  258. f1 := pih_elem(cur_leaf);
  259. Inc(cur_leaf);
  260. Dec(leaves_left);
  261. end
  262. else if (cur_inode <> next_inode) then begin
  263. f1 := cur_inode;
  264. Inc(cur_inode);
  265. end;
  266. if ((leaves_left <> 0) and
  267. ((cur_inode = next_inode) or
  268. (cur_leaf^.freq <= cur_inode^.freq))) then begin
  269. f2 := pih_elem(cur_leaf);
  270. Inc(cur_leaf);
  271. Dec(leaves_left);
  272. end
  273. else if (cur_inode <> next_inode) then begin
  274. f2 := cur_inode;
  275. Inc(cur_inode);
  276. end;
  277. if (f1 <> nil) and (f2 <> nil) then begin
  278. next_inode^.freq := f1^.freq + f2^.freq;
  279. next_inode^.sym := -1;
  280. next_inode^.left := f1;
  281. next_inode^.right := f2;
  282. next_inode^.parent := nil;
  283. f1^.parent := next_inode;
  284. f2^.parent := next_inode;
  285. if (f1^.pathlength > f2^.pathlength) then
  286. next_inode^.pathlength := f1^.pathlength + 1
  287. else
  288. next_inode^.pathlength := f2^.pathlength + 1;
  289. if (next_inode^.pathlength > max_code_length) then begin
  290. codes_too_long := 1;
  291. break;
  292. end;
  293. Inc(next_inode);
  294. end;
  295. until (f1 = nil) and (f2 = nil);
  296. until codes_too_long = 0;
  297. //* now traverse tree depth-first */
  298. cur_inode := next_inode - 1;
  299. pathlength := 0;
  300. cur_inode^.pathlength := -1;
  301. repeat
  302. //* precondition: at unmarked node*/
  303. if (cur_inode^.sym = -1) then begin //*&& (cur_inode^.left)*/
  304. //* left node of unmarked node is unmarked */
  305. cur_inode := cur_inode^.left;
  306. cur_inode^.pathlength := -1;
  307. Inc(pathlength);
  308. end
  309. else begin
  310. //* mark node */
  311. cur_inode^.pathlength := pathlength;
  312. //#if 0
  313. // if (cur_inode^.right) {
  314. // /* right node of previously unmarked node is unmarked */
  315. // cur_inode = cur_inode^.right;
  316. // cur_inode^.pathlength = -1;
  317. // pathlength++;
  318. // }
  319. // else
  320. //#endif
  321. begin
  322. //* time to come up. Keep coming up until an unmarked node is reached */
  323. //* or the tree is exhausted */
  324. repeat
  325. cur_inode := cur_inode^.parent;
  326. Dec(pathlength);
  327. //while (cur_inode && (cur_inode^.pathlength != -1));
  328. until (cur_inode = nil) or (cur_inode^.pathlength = -1);
  329. if (cur_inode <> nil) then begin
  330. //* found unmarked node; mark it and go right */
  331. cur_inode^.pathlength := pathlength;
  332. cur_inode := cur_inode^.right;
  333. cur_inode^.pathlength := -1;
  334. Inc(pathlength);
  335. //* would be complex if cur_inode could be null here. It can't */
  336. end
  337. end;
  338. end;
  339. until cur_inode = nil;
  340. freemem(inodes);
  341. ///* the pathlengths are already in order, so this sorts by symbol */
  342. qsort(leaves, nelem, @cmp_pathlengths);
  343. //#if 0
  344. // pathlength = leaves[0].pathlength;
  345. // cur_code = 0;
  346. // for (i = 0; i < nleaves; i++) {
  347. // while (leaves[i].pathlength < pathlength) {
  348. // (!(cur_code & 1));
  349. // cur_code >>= 1;
  350. // pathlength--;
  351. // }
  352. // leaves[i].code = cur_code;
  353. // cur_code++;
  354. // }
  355. //#else
  356. pathlength := leaves[nleaves-1].pathlength;
  357. if leaves[0].pathlength > 16 then
  358. raise Exception.Create('leaves[0].pathlength <= 16');
  359. //* this method cannot deal with bigger codes, though
  360. // the other canonical method can in some cases
  361. // (because it starts with zeros ) */
  362. cur_code := 0;
  363. for i := nleaves-1 downto 0 do begin
  364. while (leaves[i].pathlength > pathlength) do begin
  365. cur_code := cur_code shl 1;
  366. Inc(pathlength);
  367. end;
  368. leaves[i].code := cur_code;
  369. Inc(cur_code);
  370. end;
  371. //#endif
  372. end
  373. else if (nleaves = 1) then begin
  374. //* 0 symbols is OK (not according to doc, but according to Caie) */
  375. //* but if only one symbol is present, two symbols are required */
  376. nleaves := 2;
  377. leaves[0].pathlength := 1;
  378. leaves[1].pathlength := 1;
  379. if (leaves[1].sym > leaves[0].sym) then begin
  380. leaves[1].code := 1;
  381. leaves[0].code := 0;
  382. end
  383. else begin
  384. leaves[0].code := 1;
  385. leaves[1].code := 0;
  386. end;
  387. end;
  388. Fillchar(tree^, nelem * sizeof(huff_entry), 0);
  389. for i := 0 to nleaves-1 do begin
  390. tree[leaves[i].sym].codelength := leaves[i].pathlength;
  391. tree[leaves[i].sym].code := leaves[i].code;
  392. end;
  393. freemem(leaves);
  394. end;
  395. function lzx_get_chars(lzi: plz_info; n: longint; buf: pbyte): longint; cdecl;
  396. var
  397. //* force lz compression to stop after every block */
  398. chars_read,
  399. chars_pad: longint;
  400. lzud: plzx_data;
  401. begin
  402. lzud := plzx_data(lzi^.user_data);
  403. chars_read := lzud^.get_bytes(lzud^.in_arg, n, buf);
  404. Dec(lzud^.left_in_frame, chars_read mod LZX_FRAME_SIZE);
  405. if (lzud^.left_in_frame < 0) then
  406. Inc(lzud^.left_in_frame, LZX_FRAME_SIZE);
  407. if ((chars_read < n) and (lzud^.left_in_frame <> 0)) then begin
  408. chars_pad := n - chars_read;
  409. if (chars_pad > lzud^.left_in_frame) then chars_pad := lzud^.left_in_frame;
  410. //* never emit a full frame of padding. This prevents silliness when
  411. // lzx_compress is called when at EOF but EOF not yet detected */
  412. if (chars_pad = LZX_FRAME_SIZE) then chars_pad := 0;
  413. FillChar(buf[chars_read], chars_pad, 0);
  414. Dec(lzud^.left_in_frame, chars_pad);
  415. Inc(chars_read, chars_pad);
  416. end;
  417. lzx_get_chars := chars_read;
  418. end;
  419. function find_match_at(lzi: plz_info; loc: longint; match_len: longint; match_locp: plongint): longint;
  420. var
  421. matchb,
  422. nmatchb,
  423. c1, c2: pbyte;
  424. j: longint;
  425. begin
  426. if -match_locp^ = loc then Exit(-1);
  427. if loc < match_len then Exit(-1);
  428. matchb := lzi^.block_buf + lzi^.block_loc + match_locp^;
  429. nmatchb := lzi^.block_buf + lzi^.block_loc - loc;
  430. c1 := matchb;
  431. c2 := nmatchb;
  432. j := 0;
  433. while j < match_len do begin
  434. if c1^ <> c2^ then begin
  435. break;
  436. end;
  437. Inc(c1);
  438. Inc(c2);
  439. Inc(j);
  440. end;
  441. if (j = match_len) then begin
  442. match_locp^ := -loc;
  443. Exit(0);
  444. end;
  445. Exit(-1);
  446. end;
  447. procedure check_entropy(lzud: plzx_data; main_index: longint);
  448. var
  449. freq,
  450. n_ln_n,
  451. rn_ln2,
  452. cur_ratio: double;
  453. n: longint;
  454. begin
  455. //* delete old entropy accumulation */
  456. if (lzud^.main_freq_table[main_index] <> 1) then begin
  457. freq := double(lzud^.main_freq_table[main_index])-1;
  458. lzud^.main_entropy := lzud^.main_entropy + (freq * ln(freq));
  459. end;
  460. //* add new entropy accumulation */
  461. freq := double(lzud^.main_freq_table[main_index]);
  462. lzud^.main_entropy := lzud^.main_entropy - (freq * ln(freq));
  463. n := lzud^.block_codesp - lzud^.block_codes;
  464. if (((n and $0FFF) = 0) and (lzud^.left_in_block >= $1000)) then begin
  465. n_ln_n := (double(n) * ln(double(n)));
  466. rn_ln2 := (rloge2 / double(n));
  467. cur_ratio := (n * rn_ln2 *(n_ln_n + lzud^.main_entropy) + 24 + 3 * 80 + NUM_CHARS + (lzud^.main_tree_size-NUM_CHARS)*3 + NUM_SECONDARY_LENGTHS ) / double(n);
  468. if (cur_ratio > lzud^.last_ratio) then begin
  469. lzud^.subdivide := -1;
  470. lz_stop_compressing(lzud^.lzi);
  471. end;
  472. lzud^.last_ratio := cur_ratio;
  473. end;
  474. end;
  475. function lzx_output_match(lzi: plz_info; match_pos, match_len: longint): longint; cdecl;
  476. var
  477. lzud: plzx_data;
  478. formatted_offset,
  479. position_footer: longword;
  480. length_footer,
  481. length_header: byte;
  482. len_pos_header: word;
  483. position_slot: longint;
  484. btdt: smallint;
  485. left, right, mid: longint;
  486. label testforr;
  487. begin
  488. lzud := plzx_data(lzi^.user_data);
  489. position_footer := 0;
  490. btdt := 0;
  491. testforr:
  492. if (match_pos = -lzud^.R0) then begin
  493. match_pos := 0;
  494. formatted_offset := 0;
  495. position_slot := 0;
  496. end
  497. else if (match_pos = -lzud^.R1) then begin
  498. lzud^.R1 := lzud^.R0;
  499. lzud^.R0 := -match_pos;
  500. match_pos := 1;
  501. formatted_offset := 1;
  502. position_slot := 1;
  503. end
  504. else if (match_pos = -lzud^.R2) then begin
  505. lzud^.R2 := lzud^.R0;
  506. lzud^.R0 := -match_pos;
  507. match_pos := 2;
  508. formatted_offset := 2;
  509. position_slot := 2;
  510. end
  511. else begin
  512. if (btdt = 0) then begin
  513. btdt := 1;
  514. if (find_match_at(lzi, lzud^.R0, match_len, @match_pos) = 0) then
  515. goto testforr;
  516. if (find_match_at(lzi, lzud^.R1, match_len, @match_pos) = 0) then
  517. goto testforr;
  518. if (find_match_at(lzi, lzud^.R2, match_len, @match_pos) = 0) then
  519. goto testforr;
  520. end;
  521. formatted_offset := -match_pos + 2;
  522. if ((match_len < 3) or
  523. ((formatted_offset >= 64) and (match_len < 4)) or
  524. ((formatted_offset >= 2048) and (match_len < 5)) or
  525. ((formatted_offset >= 65536) and (match_len < 6))) then begin
  526. //* reject matches where extra_bits will likely be bigger than just outputting
  527. // literals. The numbers are basically derived through guessing
  528. // and trial and error */
  529. Exit(-1); //* reject the match */
  530. end;
  531. lzud^.R2 := lzud^.R1;
  532. lzud^.R1 := lzud^.R0;
  533. lzud^.R0 := -match_pos;
  534. ///* calculate position base using binary search of table; if log2 can be
  535. // done in hardware, approximation might work;
  536. // trunc(log2(formatted_offset*formatted_offset)) gets either the proper
  537. // position slot or the next one, except for slots 0, 1, and 39-49
  538. // Slots 0-1 are handled by the R0-R1 procedures
  539. // Slots 36-49 (formatted_offset >= 262144) can be found by
  540. // (formatted_offset/131072) + 34 ==
  541. // (formatted_offset >> 17) + 34;
  542. //*/
  543. if (formatted_offset >= 262144) then begin
  544. position_slot := (formatted_offset shr 17) + 34;
  545. end
  546. else begin
  547. left := 3;
  548. right := lzud^.num_position_slots - 1;
  549. position_slot := -1;
  550. while (left <= right) do begin
  551. mid := (left + right) div 2;
  552. if (position_base[mid] <= formatted_offset) and
  553. (position_base[mid+1] > formatted_offset) then begin
  554. position_slot := mid;
  555. break;
  556. end;
  557. if (formatted_offset > position_base[mid]) then
  558. //* too low */
  559. left := mid + 1
  560. else //* too high */
  561. right := mid;
  562. end;
  563. if not(position_slot >= 0) then
  564. raise Exception.Create('position_slot >= 0');
  565. //* FIXME precalc extra_mask table */
  566. end;
  567. position_footer := ((LongWord(1) shl extra_bits[position_slot]) - 1) and formatted_offset;
  568. end;
  569. //* match length = 8 bits */
  570. //* position_slot = 6 bits */
  571. //* position_footer = 17 bits */
  572. //* total = 31 bits */
  573. //* plus one to say whether it's a literal or not */
  574. lzud^.block_codesp^ := $80000000 or //* bit 31 in intelligent bit ordering */
  575. (position_slot shl 25) or //* bits 30-25 */
  576. (position_footer shl 8) or //* bits 8-24 */
  577. (match_len - MIN_MATCH); //* bits 0-7 */
  578. Inc(lzud^.block_codesp);
  579. if (match_len < (NUM_PRIMARY_LENGTHS + MIN_MATCH)) then begin
  580. length_header := match_len - MIN_MATCH;
  581. //* length_footer = 255; */ /* not necessary */
  582. end
  583. else begin
  584. length_header := NUM_PRIMARY_LENGTHS;
  585. length_footer := match_len - (NUM_PRIMARY_LENGTHS + MIN_MATCH);
  586. Inc(lzud^.length_freq_table[length_footer]);
  587. end;
  588. len_pos_header := (position_slot shl 3) or length_header;
  589. Inc(lzud^.main_freq_table[len_pos_header + NUM_CHARS]);
  590. if (extra_bits[position_slot] >= 3) then begin
  591. Inc(lzud^.aligned_freq_table[position_footer and 7]);
  592. end;
  593. Dec(lzud^.left_in_block, match_len);
  594. if (lzud^.subdivide <> 0) then
  595. check_entropy(lzud, len_pos_header + NUM_CHARS);
  596. Exit(0); ///* accept the match */
  597. end;
  598. procedure lzx_output_literal(lzi: plz_info; ch: byte); cdecl;
  599. var
  600. lzud: plzx_data;
  601. begin
  602. lzud := plzx_data(lzi^.user_data);
  603. Dec(lzud^.left_in_block);
  604. lzud^.block_codesp^ := ch;
  605. Inc(lzud^.block_codesp);
  606. Inc(lzud^.main_freq_table[ch]);
  607. if (lzud^.subdivide <> 0) then
  608. check_entropy(lzud, ch);
  609. end;
  610. procedure lzx_write_bits(lzxd: plzx_data; nbits: longint; bits: longword); cdecl;
  611. var
  612. cur_bits,
  613. shift_bits,
  614. rshift_bits: longint;
  615. mask_bits: word;
  616. begin
  617. cur_bits := lzxd^.bits_in_buf;
  618. while ((cur_bits + nbits) >= 16) do begin
  619. shift_bits := 16 - cur_bits;
  620. rshift_bits := nbits - shift_bits;
  621. if (shift_bits = 16) then begin
  622. lzxd^.bit_buf := (bits shr rshift_bits) and $FFFF;
  623. end
  624. else begin
  625. mask_bits := (1 shl shift_bits) - 1;
  626. lzxd^.bit_buf := lzxd^.bit_buf shl shift_bits;
  627. lzxd^.bit_buf := lzxd^.bit_buf or (bits shr rshift_bits) and mask_bits;
  628. end;
  629. {$IFDEF ENDIAN_BIG}
  630. lzxd^.bit_buf := ((lzxd^.bit_buf and $FF)shl 8) or (lzxd^.bit_buf shr 8);
  631. {$ENDIF}
  632. lzxd^.put_bytes(lzxd^.out_arg, sizeof(lzxd^.bit_buf), @lzxd^.bit_buf);
  633. Inc(lzxd^.len_compressed_output, sizeof(lzxd^.bit_buf));
  634. lzxd^.bit_buf := 0;
  635. Dec(nbits, shift_bits);
  636. cur_bits := 0;
  637. end;
  638. //* (cur_bits + nbits) < 16. If nbits := 0, we're done.
  639. // otherwise move bits in */
  640. shift_bits := nbits;
  641. mask_bits := (1 shl shift_bits) - 1;
  642. lzxd^.bit_buf := lzxd^.bit_buf shl shift_bits;
  643. lzxd^.bit_buf := lzxd^.bit_buf or bits and mask_bits;
  644. Inc(cur_bits, nbits);
  645. lzxd^.bits_in_buf := cur_bits;
  646. end;
  647. procedure lzx_align_output(lzxd: plzx_data);
  648. begin
  649. if (lzxd^.bits_in_buf <> 0) then begin
  650. lzx_write_bits(lzxd, 16 - lzxd^.bits_in_buf, 0);
  651. end;
  652. if (lzxd^.mark_frame <> nil) then
  653. lzxd^.mark_frame(lzxd^.mark_frame_arg, lzxd^.len_uncompressed_input, lzxd^.len_compressed_output);
  654. end;
  655. procedure lzx_write_compressed_literals(lzxd: plzx_data; block_type: longint);
  656. var
  657. cursor: plongword;
  658. endp: plongword;
  659. position_slot: word;
  660. position_footer,
  661. match_len_m2, //* match length minus 2, which is MIN_MATCH */
  662. verbatim_bits,
  663. block_code: longword;
  664. length_header,
  665. length_footer,
  666. len_pos_header: word;
  667. huffe: phuff_entry;
  668. frame_count: longint;
  669. begin
  670. cursor := lzxd^.block_codes;
  671. endp := lzxd^.block_codesp;
  672. frame_count := (lzxd^.len_uncompressed_input mod LZX_FRAME_SIZE);
  673. Dec(lzxd^.len_uncompressed_input, frame_count); //* will be added back in later */
  674. while (cursor < endp) do begin
  675. block_code := cursor^;
  676. Inc(cursor);
  677. if (block_code and $80000000) <> 0 then begin
  678. {*
  679. * 0x80000000 | bit 31 in intelligent bit ordering
  680. * (position_slot shl 25) | bits 30-25
  681. * (position_footer shl 8) | bits 8-24
  682. * (match_len - MIN_MATCH); bits 0-7
  683. *
  684. *}
  685. match_len_m2 := block_code and $FF; //* 8 bits */
  686. position_footer := (block_code shr 8)and $1FFFF; //* 17 bits */
  687. position_slot := (block_code shr 25) and $3F; //* 6 bits */
  688. if (match_len_m2 < NUM_PRIMARY_LENGTHS) then begin
  689. length_header := match_len_m2;
  690. length_footer := 255; //* personal encoding for NULL */
  691. end
  692. else begin
  693. length_header := NUM_PRIMARY_LENGTHS;
  694. length_footer := match_len_m2 - NUM_PRIMARY_LENGTHS;
  695. end;
  696. len_pos_header := (position_slot shl 3) or length_header;
  697. huffe := @lzxd^.main_tree[len_pos_header+NUM_CHARS];
  698. lzx_write_bits(lzxd, huffe^.codelength, huffe^.code);
  699. if (length_footer <> 255) then begin
  700. huffe := @lzxd^.length_tree[length_footer];
  701. lzx_write_bits(lzxd, huffe^.codelength, huffe^.code);
  702. end;
  703. if ((block_type = LZX_ALIGNED_OFFSET_BLOCK) and (extra_bits[position_slot] >= 3)) then begin
  704. //* aligned offset block and code */
  705. verbatim_bits := position_footer shr 3;
  706. lzx_write_bits(lzxd, extra_bits[position_slot] - 3, verbatim_bits);
  707. huffe := @lzxd^.aligned_tree[position_footer and 7];
  708. lzx_write_bits(lzxd, huffe^.codelength, huffe^.code);
  709. end
  710. else begin
  711. verbatim_bits := position_footer;
  712. lzx_write_bits(lzxd, extra_bits[position_slot], verbatim_bits);
  713. end;
  714. Inc(frame_count, match_len_m2 + 2);
  715. end
  716. else begin
  717. //* literal */
  718. if not(block_code < NUM_CHARS) then
  719. raise Exception.Create('block_code < NUM_CHARS');
  720. huffe := @lzxd^.main_tree[block_code];
  721. lzx_write_bits(lzxd, huffe^.codelength, huffe^.code);
  722. Inc(frame_count);
  723. end;
  724. if (frame_count = LZX_FRAME_SIZE) then begin
  725. Inc(lzxd^.len_uncompressed_input, frame_count);
  726. lzx_align_output(lzxd);
  727. frame_count := 0;
  728. end;
  729. if not(frame_count < LZX_FRAME_SIZE) then
  730. raise Exception.Create('frame_count < LZX_FRAME_SIZE');
  731. end;
  732. Inc(lzxd^.len_uncompressed_input, frame_count);
  733. end;
  734. function lzx_write_compressed_tree(lzxd: plzx_data; tree: phuff_entry; prevlengths: pbyte;
  735. treesize: longint): longint;
  736. var
  737. codes,
  738. runs: pbyte;
  739. freqs: array [0..LZX_PRETREE_SIZE-1] of longint;
  740. cur_run: longint;
  741. last_len: longint;
  742. pretree: array [0..19] of huff_entry;
  743. codep,
  744. codee,
  745. runp: pbyte;
  746. excess,
  747. i,
  748. cur_code: longint;
  749. begin
  750. codes := getmem(treesize*sizeof(byte));
  751. codep := codes;
  752. runs := getmem(treesize*sizeof(byte));
  753. runp := runs;
  754. Fillchar(freqs[0], sizeof(freqs), 0);
  755. cur_run := 1;
  756. last_len := tree[0].codelength;
  757. for i := 1 to treesize do begin
  758. if ((i = treesize) or (tree[i].codelength <> last_len)) then begin
  759. if (last_len = 0) then begin
  760. while (cur_run >= 20) do begin
  761. excess := cur_run - 20;
  762. if (excess > 31) then excess := 31;
  763. codep^ := 18;
  764. Inc(codep);
  765. runp^ := excess;
  766. Inc(runp);
  767. Dec(cur_run, excess + 20);
  768. Inc(freqs[18]);
  769. end;
  770. while (cur_run >= 4) do begin
  771. excess := cur_run - 4;
  772. if (excess > 15) then excess := 15;
  773. codep^ := 17;
  774. Inc(codep);
  775. runp^ := excess;
  776. Inc(runp);
  777. Dec(cur_run, excess + 4);
  778. Inc(freqs[17]);
  779. end;
  780. while (cur_run > 0) do begin
  781. codep^ := prevlengths[i - cur_run];
  782. Inc(freqs[codep^]);
  783. Inc(codep);
  784. runp^ := 0; //* not necessary */
  785. Inc(runp);
  786. Dec(cur_run);
  787. end;
  788. end
  789. else begin
  790. while (cur_run >= 4) do begin
  791. if (cur_run = 4) then excess := 0
  792. else excess := 1;
  793. codep^ := 19;
  794. Inc(codep);
  795. runp^ := excess;
  796. Inc(runp);
  797. Inc(freqs[19]);
  798. //* right, MS lies again. Code is NOT
  799. // prev_len + len (mod 17), it's prev_len - len (mod 17)*/
  800. codep^ := prevlengths[i-cur_run] - last_len;
  801. if (codep^ > 16) then Inc(codep^, 17);
  802. Inc(freqs[codep^]);
  803. Inc(codep);
  804. runp^ := 0; //* not necessary */
  805. Inc(runp);
  806. Dec(cur_run, excess+4);
  807. end;
  808. while (cur_run > 0) do begin
  809. codep^ := prevlengths[i-cur_run] - last_len;
  810. if (codep^ > 16) then Inc(codep^, 17);
  811. runp^ := 0; //* not necessary */
  812. Inc(runp);
  813. Dec(cur_run);
  814. Inc(freqs[codep^]);
  815. Inc(codep);
  816. end;
  817. end;
  818. if (i <> treesize) then
  819. last_len := tree[i].codelength;
  820. cur_run := 0;
  821. end;
  822. Inc(cur_run);
  823. end;
  824. codee := codep;
  825. //* now create the huffman table and write out the pretree */
  826. build_huffman_tree(LZX_PRETREE_SIZE, 16, @freqs[0], pretree);
  827. for i := 0 to LZX_PRETREE_SIZE-1 do begin
  828. lzx_write_bits(lzxd, 4, pretree[i].codelength);
  829. end;
  830. codep := codes;
  831. runp := runs;
  832. cur_run := 0;
  833. while (codep < codee) do begin
  834. cur_code := codep^;
  835. Inc(codep);
  836. lzx_write_bits(lzxd, pretree[cur_code].codelength, pretree[cur_code].code);
  837. if (cur_code = 17) then begin
  838. Inc(cur_run, runp^ + 4);
  839. lzx_write_bits(lzxd, 4, runp^);
  840. end
  841. else if (cur_code = 18) then begin
  842. Inc(cur_run, runp^ + 20);
  843. lzx_write_bits(lzxd, 5, runp^);
  844. end
  845. else if (cur_code = 19) then begin
  846. Inc(cur_run, runp^ + 4);
  847. lzx_write_bits(lzxd, 1, runp^);
  848. cur_code := codep^;
  849. Inc(codep);
  850. lzx_write_bits(lzxd, pretree[cur_code].codelength, pretree[cur_code].code);
  851. Inc(runp);
  852. end
  853. else begin
  854. Inc(cur_run);
  855. end;
  856. Inc(runp);
  857. end;
  858. freemem(codes);
  859. freemem(runs);
  860. Exit(0);
  861. end;
  862. procedure lzx_reset(lzxd:plzx_data);
  863. begin
  864. lzxd^.need_1bit_header := 1;
  865. lzxd^.R0 := 1;
  866. lzxd^.R1 := 1;
  867. lzxd^.R2 := 1;
  868. Fillchar(lzxd^.prev_main_treelengths[0], lzxd^.main_tree_size * sizeof(byte), 0);
  869. Fillchar(lzxd^.prev_length_treelengths[0], NUM_SECONDARY_LENGTHS * sizeof(byte), 0);
  870. lz_reset(lzxd^.lzi);
  871. end;
  872. function lzx_compress_block(lzxd:plzx_data; block_size:longint; subdivide:longbool):longint;
  873. var
  874. i: longint;
  875. written_sofar: longword = 0;
  876. block_type: longint;
  877. uncomp_bits,
  878. comp_bits,
  879. comp_bits_ovh,
  880. uncomp_length: longword;
  881. begin
  882. if ((lzxd^.block_size <> block_size) or (lzxd^.block_codes = nil)) then begin
  883. if (lzxd^.block_codes <> nil) then freemem(lzxd^.block_codes);
  884. lzxd^.block_size := block_size;
  885. lzxd^.block_codes := GetMem(block_size * sizeof(longword));
  886. end;
  887. lzxd^.subdivide := Ord(subdivide);
  888. lzxd^.left_in_block := block_size;
  889. lzxd^.left_in_frame := LZX_FRAME_SIZE;
  890. lzxd^.main_entropy := 0.0;
  891. lzxd^.last_ratio := 9999999.0;
  892. lzxd^.block_codesp := lzxd^.block_codes;
  893. Fillchar(lzxd^.length_freq_table[0], NUM_SECONDARY_LENGTHS * sizeof(longint), 0);
  894. Fillchar(lzxd^.main_freq_table[0], lzxd^.main_tree_size * sizeof(longint), 0);
  895. Fillchar(lzxd^.aligned_freq_table[0], LZX_ALIGNED_SIZE * sizeof(longint), 0);
  896. while ((lzxd^.left_in_block<>0) and ((lz_left_to_process(lzxd^.lzi)<>0) or not(lzxd^.at_eof(lzxd^.in_arg)))) do begin
  897. lz_compress(lzxd^.lzi, lzxd^.left_in_block);
  898. if (lzxd^.left_in_frame = 0) then begin
  899. lzxd^.left_in_frame := LZX_FRAME_SIZE;
  900. end;
  901. if lzxd^.at_eof(lzxd^.in_arg) then Sleep(500);
  902. if ((lzxd^.subdivide<0)
  903. or (lzxd^.left_in_block = 0)
  904. or ((lz_left_to_process(lzxd^.lzi) = 0) and lzxd^.at_eof(lzxd^.in_arg))) then begin
  905. //* now one block is LZ-analyzed. */
  906. //* time to write it out */
  907. uncomp_length := lzxd^.block_size - lzxd^.left_in_block - written_sofar;
  908. //* uncomp_length will sometimes be 0 when input length is
  909. // an exact multiple of frame size */
  910. if (uncomp_length = 0) then
  911. continue;
  912. if (lzxd^.subdivide < 0) then begin
  913. lzxd^.subdivide := 1;
  914. end;
  915. if (lzxd^.need_1bit_header <> 0) then begin
  916. //* one bit Intel preprocessing header */
  917. //* always 0 because this implementation doesn't do Intel preprocessing */
  918. lzx_write_bits(lzxd, 1, 0);
  919. lzxd^.need_1bit_header := 0;
  920. end;
  921. //* handle extra bits */
  922. uncomp_bits := 0;
  923. comp_bits := 0;
  924. build_huffman_tree(LZX_ALIGNED_SIZE, 7, @lzxd^.aligned_freq_table[0], @lzxd^.aligned_tree[0]);
  925. for i := 0 to LZX_ALIGNED_SIZE-1 do begin
  926. Inc(uncomp_bits, lzxd^.aligned_freq_table[i]* 3);
  927. Inc(comp_bits, lzxd^.aligned_freq_table[i]* lzxd^.aligned_tree[i].codelength);
  928. end;
  929. comp_bits_ovh := comp_bits + LZX_ALIGNED_SIZE * 3;
  930. if (comp_bits_ovh < uncomp_bits) then
  931. block_type := LZX_ALIGNED_OFFSET_BLOCK
  932. else
  933. block_type := LZX_VERBATIM_BLOCK;
  934. //* block type */
  935. lzx_write_bits(lzxd, 3, block_type);
  936. //* uncompressed length */
  937. lzx_write_bits(lzxd, 24, uncomp_length);
  938. written_sofar := lzxd^.block_size - lzxd^.left_in_block;
  939. //* now write out the aligned offset trees if present */
  940. if (block_type = LZX_ALIGNED_OFFSET_BLOCK) then begin
  941. for i := 0 to LZX_ALIGNED_SIZE-1 do begin
  942. lzx_write_bits(lzxd, 3, lzxd^.aligned_tree[i].codelength);
  943. end;
  944. end;
  945. //* end extra bits */
  946. build_huffman_tree(lzxd^.main_tree_size, LZX_MAX_CODE_LENGTH,
  947. lzxd^.main_freq_table, lzxd^.main_tree);
  948. build_huffman_tree(NUM_SECONDARY_LENGTHS, 16,
  949. @lzxd^.length_freq_table[0], @lzxd^.length_tree[0]);
  950. //* now write the pre-tree and tree for main 1 */
  951. lzx_write_compressed_tree(lzxd, lzxd^.main_tree, lzxd^.prev_main_treelengths, NUM_CHARS);
  952. //* now write the pre-tree and tree for main 2*/
  953. lzx_write_compressed_tree(lzxd, lzxd^.main_tree + NUM_CHARS,
  954. lzxd^.prev_main_treelengths + NUM_CHARS,
  955. lzxd^.main_tree_size - NUM_CHARS);
  956. //* now write the pre tree and tree for length */
  957. lzx_write_compressed_tree(lzxd, @lzxd^.length_tree[0], @lzxd^.prev_length_treelengths[0],
  958. NUM_SECONDARY_LENGTHS);
  959. //* now write literals */
  960. lzx_write_compressed_literals(lzxd, block_type);
  961. //* copy treelengths somewhere safe to do delta compression */
  962. for i := 0 to lzxd^.main_tree_size-1 do begin
  963. lzxd^.prev_main_treelengths[i] := lzxd^.main_tree[i].codelength;
  964. end;
  965. for i := 0 to NUM_SECONDARY_LENGTHS-1 do begin
  966. lzxd^.prev_length_treelengths[i] := lzxd^.length_tree[i].codelength;
  967. end;
  968. lzxd^.main_entropy := 0.0;
  969. lzxd^.last_ratio := 9999999.0;
  970. lzxd^.block_codesp := lzxd^.block_codes;
  971. Fillchar(lzxd^.length_freq_table[0], NUM_SECONDARY_LENGTHS * sizeof(longint), 0);
  972. Fillchar(lzxd^.main_freq_table[0], lzxd^.main_tree_size * sizeof(longint), 0);
  973. Fillchar(lzxd^.aligned_freq_table[0], LZX_ALIGNED_SIZE * sizeof(longint), 0);
  974. end;
  975. end;
  976. Exit(0);
  977. end;
  978. function lzx_init(lzxdp:Pplzx_data; wsize_code:longint; get_bytes:TGetBytesFunc; get_bytes_arg:pointer; at_eof:TIsEndOfFileFunc;
  979. put_bytes:TWriteBytesFunc; put_bytes_arg:pointer; mark_frame:TMarkFrameFunc; mark_frame_arg:pointer):longint;var
  980. wsize: longint;
  981. lzxd: plzx_data;
  982. begin
  983. if ((wsize_code < 15) or (wsize_code > 21)) then begin
  984. Exit(-1);
  985. end;
  986. //lzx_init_static(); I hardcoded this instead
  987. New(lzxd);
  988. FillChar(lzxd^, Sizeof(lzxd), 0);
  989. lzxdp^ := lzxd;
  990. if (lzxd = nil) then
  991. Exit(-2);
  992. lzxd^.in_arg := get_bytes_arg;
  993. lzxd^.out_arg := put_bytes_arg;
  994. lzxd^.mark_frame_arg := mark_frame_arg;
  995. lzxd^.get_bytes := get_bytes;
  996. lzxd^.put_bytes := put_bytes;
  997. lzxd^.at_eof := at_eof;
  998. lzxd^.mark_frame := mark_frame;
  999. wsize := 1 shl (wsize_code);
  1000. lzxd^.bits_in_buf := 0;
  1001. lzxd^.block_codes := nil;
  1002. lzxd^.num_position_slots := num_position_slots[wsize_code-15];
  1003. lzxd^.main_tree_size := (NUM_CHARS + 8 * lzxd^.num_position_slots);
  1004. lzxd^.main_freq_table := GetMem(sizeof(longint) * lzxd^.main_tree_size);
  1005. lzxd^.main_tree := GetMem(sizeof(huff_entry)* lzxd^.main_tree_size);
  1006. lzxd^.prev_main_treelengths := GetMem(sizeof(byte)*lzxd^.main_tree_size);
  1007. New(lzxd^.lzi);
  1008. //* the -3 prevents matches at wsize, wsize-1, wsize-2, all of which are illegal */
  1009. lz_init(lzxd^.lzi, wsize, wsize - 3, MAX_MATCH, MIN_MATCH, LZX_FRAME_SIZE,
  1010. @lzx_get_chars, @lzx_output_match, @lzx_output_literal,lzxd);
  1011. lzxd^.len_uncompressed_input := 0;
  1012. lzxd^.len_compressed_output := 0;
  1013. lzx_reset(lzxd);
  1014. Exit(0);
  1015. end;
  1016. function lzx_finish(lzxd:plzx_data; lzxr:plzx_results):longint;
  1017. begin
  1018. if (lzxr <> nil) then begin
  1019. lzxr^.len_compressed_output := lzxd^.len_compressed_output;
  1020. lzxr^.len_uncompressed_input := lzxd^.len_uncompressed_input;
  1021. end;
  1022. lz_release(lzxd^.lzi);
  1023. Dispose(lzxd^.lzi);
  1024. freemem(lzxd^.prev_main_treelengths);
  1025. freemem(lzxd^.main_tree);
  1026. freemem(lzxd^.main_freq_table);
  1027. dispose(lzxd);
  1028. Exit(0);
  1029. end;
  1030. initialization
  1031. rloge2 := 1.0 / ln(2);
  1032. end.