WinConvert.pas
上传用户:xjwsee
上传日期:2008-08-02
资源大小:796k
文件大小:25k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {$A+} { word align }
  2. {$O+} { ?? ?? }
  3. unit WinConvert;
  4. (*
  5.  * LZHUF.C English version 1.0
  6.  * Based on Japanese version 29-NOV-1988
  7.  * LZSS coded by Haruhiko OKUMURA
  8.  * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI
  9.  * Edited and translated to English by Kenji RIKITAKE
  10.  * Translated from C to Turbo Pascal by Douglas Webb   2/18/91
  11.  *    Update and bug correction of TP version 4/29/91 (Sorry!!)
  12.  *    Added Delphi exception handling may 09 1996 Danny Heijl
  13.  *                                                Danny.Heijl@cevi.be
  14.  * Added support for Delphi streams Aug. 05 1999
  15.  *    Bruno Depero (bdepero@usa.net) and
  16.  *    Kim Madsen (kbm@optical.dk)
  17.  *)
  18. {
  19.      This unit allows the user to compress data using a combination of
  20.    LZSS compression and adaptive Huffman coding, or conversely to decompress
  21.    data that was previously compressed by this unit.
  22.      There are a number of options as to where the data being compressed/
  23.    decompressed is coming from/going to.
  24.    In fact it requires that you pass the "LZHPack" procedure 2 procedural
  25.   parameter of type 'GetProcType' and 'PutProcType' (declared below) which
  26.   will accept 3 parameters and act in every way like a 'BlockRead'/
  27.   'BlockWrite' procedure call. Your 'GetBytesProc' procedure should return
  28.   the data to be compressed, and Your 'PutBytesProc' procedure should do
  29.   something with the compressed data (ie., put it in a file).  In case you
  30.   need to know (and you do if you want to decompress this data again) the
  31.   number of bytes in the compressed data (original, not compressed size)
  32.   is returned in 'Bytes_Written'.
  33.   GetBytesProc = PROCEDURE(VAR DTA; NBytes:WORD; VAR Bytes_Got : WORD);
  34.   DTA is the start of a memory location where the information returned
  35.   should be.  NBytes is the number of bytes requested.  The actual number
  36.   of bytes returned must be passed in Bytes_Got (if there is no more data
  37.   then 0 should be returned).
  38.   PutBytesProc = PROCEDURE(VAR DTA; NBytes:WORD; VAR Bytes_Got : WORD);
  39.   As above except instead of asking for data the procedure is dumping out
  40.   compressed data, do somthing with it.
  41.    "LZHUnPack" is basically the same thing in reverse.  It requires
  42.   procedural parameters of type 'PutProcType'/'GetProcType' which
  43.   will act as above.  'GetProcType' must retrieve data compressed using
  44.   "LZHPack" (above) and feed it to the unpacking routine as requested.
  45.   'PutProcType' must accept the decompressed data and do something
  46.   withit.  You must also pass in the original size of the decompressed data,
  47.   failure to do so will have adverse results.
  48.    Don't forget that as procedural parameters the 'GetProcType'/'PutProcType'
  49.   procedures must be compiled in the 'F+' state to avoid a catastrophe.
  50. }
  51. { Note: All the large data structures for these routines are allocated when
  52.   needed from the heap, and deallocated when finished.  So when not in use
  53.   memory requirements are minimal.  However, this unit uses about 34K of
  54.   heap space, and 400 bytes of stack when in use. }
  55. {$R-} { NO range checking !! }
  56. interface
  57. uses Sysutils,Classes;
  58. {$IFDEF WIN32}
  59. type Int16 = SmallInt;
  60. {$ELSE}
  61. type Int16 = Integer;
  62. {$ENDIF}
  63. {.$DEFINE DEBUG}
  64. {$IFDEF DEBUG}
  65.   {$D+}
  66. {$ENDIF}
  67. TYPE
  68.   ElzhException = Class(Exception);
  69.   TWriteProc = procedure(VAR DTA; NBytes:WORD; VAR Bytes_Put : WORD) of object;
  70.   PutBytesProc = TwriteProc;
  71.   {
  72.    Your 'PutBytesProc' procedure should do something with the compressed
  73.    data (ie., put it in a file).
  74.    DTA is the start of a memory location where the information returned
  75.    should be.  NBytes is the number of bytes requested.  The actual number
  76.    of bytes put should be returned in Bytes_Got.
  77.    Don't forget that as procedural parameters the 'GetProcType'/'PutProcType'
  78.   procedures must be compiled in the 'F+' state to avoid a catastrophe.
  79.   }
  80.   TReadProc = procedure(VAR DTA; NBytes:WORD; VAR Bytes_Got : WORD) of object;
  81.   GetBytesProc = TReadProc;
  82.   {
  83.    Your 'GetBytesProc' procedure should return the data to be compressed.
  84.    In case you need to know (and you do if you want to decompress this
  85.    data again) the number of bytes in the compressed data (original, not
  86.    compressed size) is returned in 'Bytes_Written'.
  87.    DTA is the start of a memory location where the information returned
  88.    should be.  NBytes is the number of bytes requested.  The actual number
  89.    of bytes returned must be passed in Bytes_Got (if there is no more data
  90.    then 0 should be returned).
  91.    Don't forget that as procedural parameters the 'GetProcType'/'PutProcType'
  92.   procedures must be compiled in the 'F+' state to avoid a catastrophe.
  93.   }
  94. CONST
  95.   EXIT_OK = 0;
  96.   EXIT_FAILED = 1;
  97. { LZSS Parameters }
  98.   N         = 4096; { Size of string buffer }
  99.   F         = 60;    { Size of look-ahead buffer }
  100.   THRESHOLD   = 2;
  101.   NUL           = N;    { End of tree's node  }
  102. { Huffman coding parameters }
  103.   N_CHAR   = (256 - THRESHOLD + F);
  104.                          { character code (:= 0..N_CHAR-1) }
  105.   T     = (N_CHAR * 2 - 1);  { Size of table }
  106.   R     = (T - 1);        { root position }
  107.   MAX_FREQ = $8000;
  108.                { update when cumulative frequency }
  109.                { reaches to this value }
  110. {
  111.  * Tables FOR encoding/decoding upper 6 bits of
  112.  * sliding dictionary pointer
  113.  }
  114. { encoder table }
  115.   p_len : Array[0..63] of BYTE =
  116.        ($03, $04, $04, $04, $05, $05, $05, $05,
  117. $05, $05, $05, $05, $06, $06, $06, $06,
  118. $06, $06, $06, $06, $06, $06, $06, $06,
  119. $07, $07, $07, $07, $07, $07, $07, $07,
  120. $07, $07, $07, $07, $07, $07, $07, $07,
  121. $07, $07, $07, $07, $07, $07, $07, $07,
  122. $08, $08, $08, $08, $08, $08, $08, $08,
  123. $08, $08, $08, $08, $08, $08, $08, $08);
  124.   p_code : Array [0..63] OF BYTE =
  125.        ($00, $20, $30, $40, $50, $58, $60, $68,
  126. $70, $78, $80, $88, $90, $94, $98, $9C,
  127. $A0, $A4, $A8, $AC, $B0, $B4, $B8, $BC,
  128. $C0, $C2, $C4, $C6, $C8, $CA, $CC, $CE,
  129. $D0, $D2, $D4, $D6, $D8, $DA, $DC, $DE,
  130. $E0, $E2, $E4, $E6, $E8, $EA, $EC, $EE,
  131. $F0, $F1, $F2, $F3, $F4, $F5, $F6, $F7,
  132. $F8, $F9, $FA, $FB, $FC, $FD, $FE, $FF);
  133. { decoder table }
  134.   d_code: Array [0..255] OF BYTE =
  135.        ($00, $00, $00, $00, $00, $00, $00, $00,
  136. $00, $00, $00, $00, $00, $00, $00, $00,
  137. $00, $00, $00, $00, $00, $00, $00, $00,
  138. $00, $00, $00, $00, $00, $00, $00, $00,
  139. $01, $01, $01, $01, $01, $01, $01, $01,
  140. $01, $01, $01, $01, $01, $01, $01, $01,
  141. $02, $02, $02, $02, $02, $02, $02, $02,
  142. $02, $02, $02, $02, $02, $02, $02, $02,
  143. $03, $03, $03, $03, $03, $03, $03, $03,
  144. $03, $03, $03, $03, $03, $03, $03, $03,
  145. $04, $04, $04, $04, $04, $04, $04, $04,
  146. $05, $05, $05, $05, $05, $05, $05, $05,
  147. $06, $06, $06, $06, $06, $06, $06, $06,
  148. $07, $07, $07, $07, $07, $07, $07, $07,
  149. $08, $08, $08, $08, $08, $08, $08, $08,
  150. $09, $09, $09, $09, $09, $09, $09, $09,
  151. $0A, $0A, $0A, $0A, $0A, $0A, $0A, $0A,
  152. $0B, $0B, $0B, $0B, $0B, $0B, $0B, $0B,
  153. $0C, $0C, $0C, $0C, $0D, $0D, $0D, $0D,
  154. $0E, $0E, $0E, $0E, $0F, $0F, $0F, $0F,
  155. $10, $10, $10, $10, $11, $11, $11, $11,
  156. $12, $12, $12, $12, $13, $13, $13, $13,
  157. $14, $14, $14, $14, $15, $15, $15, $15,
  158. $16, $16, $16, $16, $17, $17, $17, $17,
  159. $18, $18, $19, $19, $1A, $1A, $1B, $1B,
  160. $1C, $1C, $1D, $1D, $1E, $1E, $1F, $1F,
  161. $20, $20, $21, $21, $22, $22, $23, $23,
  162. $24, $24, $25, $25, $26, $26, $27, $27,
  163. $28, $28, $29, $29, $2A, $2A, $2B, $2B,
  164. $2C, $2C, $2D, $2D, $2E, $2E, $2F, $2F,
  165. $30, $31, $32, $33, $34, $35, $36, $37,
  166. $38, $39, $3A, $3B, $3C, $3D, $3E, $3F);
  167.  d_len: Array[0..255] of BYTE =
  168.        ($03, $03, $03, $03, $03, $03, $03, $03,
  169. $03, $03, $03, $03, $03, $03, $03, $03,
  170. $03, $03, $03, $03, $03, $03, $03, $03,
  171. $03, $03, $03, $03, $03, $03, $03, $03,
  172. $04, $04, $04, $04, $04, $04, $04, $04,
  173. $04, $04, $04, $04, $04, $04, $04, $04,
  174. $04, $04, $04, $04, $04, $04, $04, $04,
  175. $04, $04, $04, $04, $04, $04, $04, $04,
  176. $04, $04, $04, $04, $04, $04, $04, $04,
  177. $04, $04, $04, $04, $04, $04, $04, $04,
  178. $05, $05, $05, $05, $05, $05, $05, $05,
  179. $05, $05, $05, $05, $05, $05, $05, $05,
  180. $05, $05, $05, $05, $05, $05, $05, $05,
  181. $05, $05, $05, $05, $05, $05, $05, $05,
  182. $05, $05, $05, $05, $05, $05, $05, $05,
  183. $05, $05, $05, $05, $05, $05, $05, $05,
  184. $05, $05, $05, $05, $05, $05, $05, $05,
  185. $05, $05, $05, $05, $05, $05, $05, $05,
  186. $06, $06, $06, $06, $06, $06, $06, $06,
  187. $06, $06, $06, $06, $06, $06, $06, $06,
  188. $06, $06, $06, $06, $06, $06, $06, $06,
  189. $06, $06, $06, $06, $06, $06, $06, $06,
  190. $06, $06, $06, $06, $06, $06, $06, $06,
  191. $06, $06, $06, $06, $06, $06, $06, $06,
  192. $07, $07, $07, $07, $07, $07, $07, $07,
  193. $07, $07, $07, $07, $07, $07, $07, $07,
  194. $07, $07, $07, $07, $07, $07, $07, $07,
  195. $07, $07, $07, $07, $07, $07, $07, $07,
  196. $07, $07, $07, $07, $07, $07, $07, $07,
  197. $07, $07, $07, $07, $07, $07, $07, $07,
  198. $08, $08, $08, $08, $08, $08, $08, $08,
  199. $08, $08, $08, $08, $08, $08, $08, $08);
  200. TYPE
  201.   Freqtype = Array[0..T] OF WORD;
  202.   FreqPtr = ^freqtype;
  203.   PntrType = Array[0..PRED(T+N_Char)] OF Int16;
  204.   pntrPtr = ^pntrType;
  205.   SonType = Array[0..PRED(T)] OF Int16;
  206.   SonPtr = ^SonType;
  207.   TextBufType = Array[0..N+F-2] OF BYTE;
  208.   TBufPtr = ^TextBufType;
  209.   WordRay = Array[0..N] OF Int16;
  210.   WordRayPtr = ^WordRay;
  211.   BWordRay = Array[0..N+256] OF Int16;
  212.   BWordRayPtr = ^BWordRay;
  213.   {PG 17/09/98}
  214.   TLZH = class
  215.   Private
  216.     code, len : WORD;
  217.     Procedure InitTree;  { Initializing tree }
  218.     Procedure InsertNode(r : Int16);  { Inserting node to the tree }
  219.     Procedure DeleteNode(p: Int16);  { Deleting node from the tree }
  220.     Function GetBit(GetBytes:GetBytesProc): Int16; { get one bit }
  221.     Function GetByte(GetBytes:GetBytesProc): Int16; { get a byte }
  222.     Procedure update(c : Int16);
  223.     Procedure StartHuff;
  224.     PROCEDURE Putcode(l : Int16; c: WORD;PutBytes:PutBytesProc); { output c bits }
  225.     PROCEDURE reconst;
  226.     PROCEDURE EncodeChar(c: WORD;PutBytes:PutBytesProc);
  227.     Procedure EncodePosition(c : WORD;PutBytes:PutBytesProc);
  228.     Procedure EncodeEnd(PutBytes:PutBytesProc);
  229.     FUNCTION DecodeChar(GetBytes:GetBytesProc): Int16;
  230.     Function DecodePosition(GetBytes:GetBytesProc) : WORD;
  231.     Procedure InitLZH;
  232.     Procedure EndLZH;
  233.   Public
  234.     StreamIn,StreamOut:TStream;
  235.     
  236.     getbuf : WORD;
  237.     getlen : BYTE;
  238.     putlen : BYTE;
  239.     putbuf : WORD;
  240.     textsize : longint;
  241.     codesize : longINT;
  242.     printcount : longint ;
  243.     match_position : Int16 ;
  244.     match_length : Int16;
  245.     text_buf : TBufPtr;
  246.     lson,dad : WordRayPtr;
  247.     rson : BWordRayPtr;
  248.     freq : FreqPtr; { cumulative freq table }
  249.   {
  250.    * pointing parent nodes.
  251.    * area [T..(T + N_CHAR - 1)] are pointers FOR leaves
  252.    }
  253.     prnt : PntrPtr;
  254.   { pointing children nodes (son[], son[] + 1)}
  255.     son : SonPtr;
  256.     Procedure LZHPack(VAR Bytes_Written:LongInt; GetBytes:GetBytesProc;
  257.                                                  PutBytes:PutBytesProc);
  258.       {#XLZHUnPack}
  259.       {
  260.          This procedure allows the user to compress data using a combination of
  261.        LZSS compression and adaptive Huffman coding.
  262.          There are a number of options as to where the data being compressed
  263.       is coming from.
  264.        In fact it requires that you pass the "LZHPack" procedure 2 procedural
  265.       parameter of type 'GetProcType' and 'PutProcType' (declared below) which
  266.       will accept 3 parameters and act in every way like a 'BlockRead'/
  267.       'BlockWrite' procedure call. Your 'GetBytesProc' procedure should return
  268.       the data to be compressed, and Your 'PutBytesProc' procedure should do
  269.       something with the compressed data (ie., put it in a file).  In case you
  270.       need to know (and you do if you want to decompress this data again) the
  271.       number of bytes in the compressed data (original, not compressed size)
  272.       is returned in 'Bytes_Written'.
  273.       DTA is the start of a memory location where the information returned
  274.       should be.  NBytes is the number of bytes requested.  The actual number
  275.       of bytes returned must be passed in Bytes_Got (if there is no more data
  276.       then 0 should be returned).
  277.       As above except instead of asking for data the procedure is dumping out
  278.       compressed data, do somthing with it.
  279.       }
  280.     Procedure LZHUnpack(TextSize : Longint; GetBytes:GetBytesProc;
  281.                                             PutBytes: PutBytesProc);
  282.       {#X LZHPack}
  283.       {
  284.         "LZHUnPack" is basically the same as LZHPack in reverse.  It requires
  285.       procedural parameters of type 'PutProcType'/'GetProcType' which
  286.       will act as above.  'GetProcType' must retrieve data compressed using
  287.       "LZHPack" (above) and feed it to the unpacking routine as requested.
  288.       'PutProcType' must accept the decompressed data and do something
  289.       withit.  You must also pass in the original size of the decompressed data,
  290.       failure to do so will have adverse results.
  291.       }
  292.     procedure GetBlockStream(var DTA; NBytes: Word; var Bytes_Got: Word);
  293.     procedure PutBlockStream(var DTA; NBytes: Word; var Bytes_Got: Word);
  294.   End;
  295. implementation
  296. Procedure TLZH.InitTree;  { Initializing tree }
  297. VAR
  298.   i : Int16;
  299. BEGIN
  300.   FOR i := N + 1 TO N + 256  DO rson^[i] := NUL; { root }
  301.   FOR i := 0 TO N DO dad^[i] := NUL; { node }
  302. END;
  303. Procedure TLZH.InsertNode(r : Int16);  { Inserting node to the tree }
  304. VAR
  305.   tmp,i, p, cmp : Int16;
  306.   key : TBufPtr;
  307.   c : WORD;
  308. BEGIN
  309.   cmp := 1;
  310.   key := @text_buf^[r];
  311.   p := SUCC(N) + key^[0];
  312.   rson^[r] := NUL;
  313.   lson^[r] := NUL;
  314.   match_length := 0;
  315.   WHILE match_length < F DO BEGIN
  316.     IF (cmp >= 0) THEN BEGIN
  317.     IF (rson^[p] <> NUL) THEN begin
  318.         p := rson^[p]
  319.       end
  320.     ELSE BEGIN
  321.       rson^[p] := r;
  322.     dad^[r] := p;
  323.     exit;
  324.       END;
  325.     END
  326.     ELSE BEGIN
  327.       IF (lson^[p] <> NUL) THEN  begin
  328.        p := lson^[p]
  329.       end
  330.       ELSE BEGIN
  331.         lson^[p] := r;
  332.     dad^[r] := p;
  333.     exit;
  334.       END;
  335.     END;
  336.     i := 0;
  337.     cmp := 0;
  338.   While (i < F) AND (cmp = 0) DO BEGIN
  339.       inc(i);
  340.       cmp := key^[i] - text_buf^[p + i];
  341.     END;
  342.     IF (i > THRESHOLD) THEN BEGIN
  343.       tmp := PRED((r - p) AND PRED(N));
  344.     IF (i > match_length) THEN BEGIN
  345.         match_position := tmp;
  346.         match_length := i;
  347.       END;
  348.     IF (match_length < F) AND (i = match_length) THEN BEGIN
  349.         c := tmp;
  350.     IF (c < match_position) THEN begin
  351.           match_position := c;
  352.         end;
  353.       END;
  354.     END; { if i > threshold }
  355.   END; { WHILE match_length < F }
  356.   dad^[r] := dad^[p];
  357.   lson^[r] := lson^[p];
  358.   rson^[r] := rson^[p];
  359.   dad^[lson^[p]] := r;
  360.   dad^[rson^[p]] := r;
  361.   IF (rson^[dad^[p]] = p) THEN begin
  362.        rson^[dad^[p]] := r;
  363.   end
  364.   ELSE begin
  365.     lson^[dad^[p]] := r;
  366.   end;
  367.   dad^[p] := NUL;  { remove p }
  368. END;
  369. Procedure TLZH.DeleteNode(p: Int16);  { Deleting node from the tree }
  370. VAR
  371.   q : Int16;
  372. BEGIN
  373.   IF (dad^[p] = NUL) THEN exit; { unregistered }
  374.   IF (rson^[p] = NUL) THEN begin
  375.    q := lson^[p];
  376.   end
  377.   ELSE begin
  378.     IF (lson^[p] = NUL) THEN begin
  379.       q := rson^[p];
  380.     end
  381.     ELSE BEGIN
  382.       q := lson^[p];
  383.       IF (rson^[q] <> NUL) THEN BEGIN
  384.         REPEAT
  385.           q := rson^[q];
  386.         UNTIL (rson^[q] = NUL);
  387.         rson^[dad^[q]] := lson^[q];
  388.         dad^[lson^[q]] := dad^[q];
  389.         lson^[q] := lson^[p];
  390.         dad^[lson^[p]] := q;
  391.       END;
  392.       rson^[q] := rson^[p];
  393.       dad^[rson^[p]] := q;
  394.     END;
  395.   end;
  396.   dad^[q] := dad^[p];
  397.   IF (rson^[dad^[p]] = p) THEN
  398.     rson^[dad^[p]] := q
  399.   ELSE
  400.     lson^[dad^[p]] := q;
  401.   dad^[p] := NUL;
  402. END;
  403. { Huffman coding parameters }
  404. Function TLZH.GetBit(GetBytes:GetBytesProc): Int16; { get one bit }
  405. VAR
  406.   i: BYTE;
  407.   i2 : Int16;
  408.   Wresult : Word;
  409. BEGIN
  410.   WHILE (getlen <= 8) DO BEGIN
  411.     GetBytes(i,1,Wresult);
  412.     If Wresult = 1 THEN
  413.       i2 := i
  414.     ELSE
  415.       i2 := 0;
  416.     getbuf := getbuf OR (i2 SHL (8 - getlen));
  417.     INC(getlen,8);
  418.   END;
  419.   i2 := getbuf;
  420.   getbuf := getbuf SHL 1;
  421.   DEC(getlen);
  422.   getbit := Int16((i2 < 0));
  423. END;
  424. Function TLZH.GetByte(GetBytes:GetBytesProc): Int16; { get a byte }
  425. VAR
  426.   j : BYTE;
  427.   i,Wresult : WORD;
  428. BEGIN
  429.   WHILE (getlen <= 8) DO BEGIN
  430.     GetBytes(j,1,Wresult);
  431.     If Wresult = 1 THEN
  432.       i := j
  433.     ELSE
  434.       i := 0;
  435.     getbuf := getbuf OR (i SHL (8 - getlen));
  436.     INC(getlen,8);
  437.   END;
  438.   i := getbuf;
  439.   getbuf := getbuf SHL 8;
  440.   DEC(getlen,8);
  441.   getbyte := Int16(i SHR 8);
  442. END;
  443. PROCEDURE TLZH.Putcode(l : Int16; c: WORD;PutBytes:PutBytesProc); { output c bits }
  444. VAR
  445.   Temp : BYTE;
  446.   Got : WORD;
  447. BEGIN
  448.   putbuf := putbuf OR (c SHR putlen);
  449.   inc(putlen,l);
  450.   IF (putlen >= 8) THEN BEGIN
  451.     Temp := putbuf SHR 8;
  452.     PutBytes(Temp,1,Got);
  453.     DEC(putlen,8);
  454.     IF (putlen  >= 8) THEN BEGIN
  455.       Temp := Lo(PutBuf);
  456.       PutBytes(Temp,1,Got);
  457.       INC(codesize,2);
  458.       DEC(putlen,8);
  459.       putbuf := c SHL (l - putlen);
  460.     END
  461.     ELSE BEGIN
  462.     putbuf := putbuf SHL 8;
  463.     INC(codesize);
  464.     END;
  465.   END;
  466. END;
  467. { initialize freq tree }
  468. Procedure TLZH.StartHuff;
  469. VAR
  470.   i, j : Int16;
  471. BEGIN
  472.   FOR i := 0 to PRED(N_CHAR) DO BEGIN
  473.     freq^[i] := 1;
  474.     son^[i] := i + T;
  475.     prnt^[i + T] := i;
  476.   END;
  477.   i := 0;
  478.   j := N_CHAR;
  479.   WHILE (j <= R) DO BEGIN
  480.     freq^[j] := freq^[i] + freq^[i + 1];
  481.     son^[j] := i;
  482.     prnt^[i] := j;
  483.     prnt^[i + 1] := j;
  484.     INC(i,2);
  485.     INC(j);
  486.   END;
  487.   freq^[T] := $ffff;
  488.   prnt^[R] := 0;
  489. END;
  490. { reconstruct freq tree }
  491. PROCEDURE TLZH.reconst;
  492. VAR
  493.  i, j, k, tmp : Int16;
  494.  f, l : WORD;
  495. BEGIN
  496.  { halven cumulative freq FOR leaf nodes }
  497.   j := 0;
  498.   FOR i := 0 to PRED(T) DO BEGIN
  499.     IF (son^[i] >= T) THEN BEGIN
  500.       freq^[j] := SUCC(freq^[i]) DIV 2;    {@@ Bug Fix MOD -> DIV @@}
  501.       son^[j] := son^[i];
  502.       INC(j);
  503.     END;
  504.   END;
  505.   { make a tree : first, connect children nodes }
  506.   i := 0;
  507.   j := N_CHAR;
  508.   WHILE (j < T) DO BEGIN
  509.     k := SUCC(i);
  510.     f := freq^[i] + freq^[k];
  511.     freq^[j] := f;
  512.     k := PRED(j);
  513.     WHILE f < freq^[k] DO DEC(K);
  514.     INC(k);
  515.     l := (j - k) SHL 1;
  516.     tmp := SUCC(k);
  517.     move(freq^[k], freq^[tmp], l);
  518.     freq^[k] := f;
  519.     move(son^[k], son^[tmp], l);
  520.     son^[k] := i;
  521.     INC(i,2);
  522.     INC(j);
  523.   END;
  524.      { connect parent nodes }
  525.   FOR i := 0 to PRED(T) DO BEGIN
  526.     k := son^[i];
  527.     IF (k >= T) THEN BEGIN
  528.     prnt^[k] := i;
  529.     END
  530.     ELSE BEGIN
  531.     prnt^[k] := i;
  532.       prnt^[SUCC(k)] := i;
  533.   END;
  534.   END;
  535. END;
  536. { update freq tree }
  537. Procedure TLZH.update(c : Int16);
  538. VAR
  539.   i, j, k, l : Int16;
  540. BEGIN
  541.   IF (freq^[R] = MAX_FREQ) THEN BEGIN
  542.     reconst;
  543.   END;
  544.   c := prnt^[c + T];
  545.   REPEAT
  546.    INC(freq^[c]);
  547.    k := freq^[c];
  548. { swap nodes to keep the tree freq-ordered }
  549.    l := SUCC(C);
  550.    IF (k > freq^[l]) THEN BEGIN
  551.      WHILE (k > freq^[l]) DO INC(l);
  552.      DEC(l);
  553.      freq^[c] := freq^[l];
  554.      freq^[l] := k;
  555.      i := son^[c];
  556.      prnt^[i] := l;
  557.      IF (i < T) THEN prnt^[SUCC(i)] := l;
  558.      j := son^[l];
  559.      son^[l] := i;
  560.      prnt^[j] := c;
  561.      IF (j < T) THEN prnt^[SUCC(j)] := c;
  562.      son^[c] := j;
  563.      c := l;
  564.    END;
  565.    c := prnt^[c];
  566.  UNTIL (c = 0); { REPEAT it until reaching the root }
  567. END;
  568. PROCEDURE TLZH.EncodeChar(c: WORD;PutBytes:PutBytesProc);
  569. VAR
  570.   i : WORD;
  571.   j, k : Int16;
  572. BEGIN
  573.   i := 0;
  574.   j := 0;
  575.   k := prnt^[c + T];
  576. { search connections from leaf node to the root }
  577.   REPEAT
  578.     i := i SHR 1;
  579. {
  580. IF node's address is odd, output 1
  581. ELSE output 0
  582. }
  583.     IF BOOLEAN(k AND 1) THEN INC(i,$8000);
  584.     INC(j);
  585.     k := prnt^[k];
  586.   UNTIL (k = R);
  587.   Putcode(j, i,PutBytes);
  588.   code := i;
  589.   len := j;
  590.   update(c);
  591. END;
  592. Procedure TLZH.EncodePosition(c : WORD;PutBytes:PutBytesProc);
  593. VAR
  594.   i,j : WORD;
  595. BEGIN
  596. { output upper 6 bits with encoding }
  597.   i := c SHR 6;
  598.   j := p_code[i];
  599.   Putcode(p_len[i],j SHL 8,PutBytes);
  600. { output lower 6 bits directly }
  601.   Putcode(6, (c AND $3f) SHL 10,PutBytes);
  602. END;
  603. Procedure TLZH.EncodeEnd(PutBytes:PutBytesProc);
  604. VAR
  605.   Temp : BYTE;
  606.   Got : WORD;
  607. BEGIN
  608.   IF BOOLEAN(putlen) THEN BEGIN
  609.     Temp := Lo(putbuf SHR 8);
  610.     PutBytes(Temp,1,Got);
  611.     INC(codesize);
  612.   END;
  613. END;
  614. FUNCTION TLZH.DecodeChar(GetBytes:GetBytesProc): Int16;
  615. VAR
  616.   c : WORD;
  617. BEGIN
  618.   c := son^[R];
  619.     {
  620.      * start searching tree from the root to leaves.
  621.      * choose node #(son[]) IF input bit = 0
  622.      * ELSE choose #(son[]+1) (input bit = 1)
  623.     }
  624.   WHILE (c < T) DO BEGIN
  625.     c := c + GetBit(GetBytes);
  626.     c := son^[c];
  627.   END;
  628.   c := c - T;
  629.   update(c);
  630.   Decodechar := Int16(c);
  631. END;
  632. Function TLZH.DecodePosition(GetBytes:GetBytesProc) : WORD;
  633. VAR
  634.   i, j, c : WORD;
  635. BEGIN
  636.      { decode upper 6 bits from given table }
  637.   i := GetByte(GetBytes);
  638.   c := WORD(d_code[i] SHL 6);
  639.   j := d_len[i];
  640. { input lower 6 bits directly }
  641.   DEC(j,2);
  642.   While j <> 0 DO BEGIN
  643.     i := (i SHL 1) + GetBit(GetBytes);
  644.     DEC(J);
  645.   END;
  646.   DecodePosition := c OR i AND $3f;
  647. END;
  648. { Compression }
  649. Procedure TLZH.InitLZH;
  650. BEGIN
  651.   getbuf := 0;
  652.   getlen := 0;
  653.   putlen := 0;
  654.   putbuf := 0;
  655.   textsize := 0;
  656.   codesize := 0;
  657.   printcount := 0;
  658.   match_position := 0;
  659.   match_length := 0;
  660.   try
  661.     New(lson);
  662.     New(dad);
  663.     New(rson);
  664.     New(text_buf);
  665.     New(freq);
  666.     New(prnt);
  667.     New(son);
  668.   except
  669.     Raise ElzhException.Create('LZH : Cannot get memory for dictionary tables');
  670.   end;
  671. END;
  672. Procedure TLZH.EndLZH;
  673. BEGIN
  674.   try
  675.     Dispose(son);
  676.     Dispose(prnt);
  677.     Dispose(freq);
  678.     Dispose(text_buf);
  679.     Dispose(rson);
  680.     Dispose(dad);
  681.     Dispose(lson);
  682.   except
  683.     Raise ElzhException.Create('LZH : Error freeing memory for dictionary tables');
  684.   end;
  685. END;
  686. Procedure TLZH.LZHPack(VAR Bytes_Written:LongInt; GetBytes:GetBytesProc; PutBytes:PutBytesProc);
  687. VAR
  688.    ct : BYTE;
  689.    i, len, r, s, last_match_length : Int16;
  690.    Got : WORD;
  691. BEGIN
  692.    InitLZH;
  693.    try
  694.      textsize := 0; { rewind and rescan }
  695.      StartHuff;
  696.      InitTree;
  697.      s := 0;
  698.      r := N - F;
  699.      FillChar(Text_buf^[0],r,' ');
  700.      len := 0;
  701.      Got := 1;
  702.      While (len < F) AND (Got <> 0) DO BEGIN
  703.        GetBytes(ct,1,Got);
  704.        IF Got <> 0 THEN BEGIN
  705.          text_buf^[r + len] := ct;
  706.          INC(len);
  707.        END;
  708.      END;
  709.      textsize := len;
  710.      FOR i := 1 to F DO begin
  711.        InsertNode(r - i);
  712.      end;
  713.      InsertNode(r);
  714.      REPEAT
  715.        IF (match_length > len) THEN begin
  716.          match_length := len;
  717.        end;
  718.        IF (match_length <= THRESHOLD) THEN BEGIN
  719.          match_length := 1;
  720.                EncodeChar(text_buf^[r],PutBytes);
  721.        END
  722.        ELSE BEGIN
  723.          EncodeChar(255 - THRESHOLD + match_length,PutBytes);
  724.                EncodePosition(match_position,PutBytes);
  725.        END;
  726.        last_match_length := match_length;
  727.        i := 0;
  728.        Got := 1;
  729.        While (i < last_match_length) AND (Got <> 0) DO BEGIN
  730.          GetBytes(ct,1,Got);
  731.          IF Got <> 0 THEN BEGIN
  732.            DeleteNode(s);
  733.            text_buf^[s] := ct;
  734.            IF (s < PRED(F)) THEN begin
  735.              text_buf^[s + N] := ct;
  736.            end;
  737.            s := SUCC(s) AND PRED(N);
  738.            r := SUCC(r) AND PRED(N);
  739.            InsertNode(r);
  740.            inc(i);
  741.          END;
  742.        END; { endwhile }
  743.        INC(textsize,i);
  744.        While (i < last_match_length) DO BEGIN
  745.          INC(i);
  746.          DeleteNode(s);
  747.          s := SUCC(s) AND PRED(N);
  748.          r := SUCC(r) AND PRED(N);
  749.          DEC(len);
  750.          IF BOOLEAN(len) THEN InsertNode(r);
  751.        END; { endwhile }
  752.      UNTIL (len <= 0);  { end repeat }
  753.      EncodeEnd(PutBytes);
  754.    finally
  755.      EndLZH;
  756.    end;
  757.    Bytes_Written := TextSize;
  758. END;
  759. Procedure TLZH.LZHUnpack(TextSize : Longint; GetBytes:GetBytesProc; PutBytes: PutBytesProc);
  760. VAR
  761.   c, i, j, k, r : Int16;
  762.   c2            : Byte;
  763.   count         : Longint;
  764.   Put           : Word;
  765. BEGIN
  766.    InitLZH;
  767.    try
  768.      StartHuff;
  769.      r := N - F;
  770.      FillChar(text_buf^[0],r,' ');
  771.      Count := 0;
  772.      While count < textsize DO BEGIN
  773.        c := DecodeChar(GetBytes);
  774.        IF (c < 256) THEN BEGIN
  775.          c2 := Lo(c);
  776.                PutBytes(c2,1,Put);
  777.                text_buf^[r] := c;
  778.          INC(r);
  779.                r := r AND PRED(N);
  780.                INC(count);
  781.        END
  782.        ELSE BEGIN                {c >= 256 }
  783.                i := (r - SUCC(DecodePosition(GetBytes))) AND PRED(N);
  784.                j := c - 255 + THRESHOLD;
  785.                FOR k := 0 TO PRED(j) DO BEGIN
  786.                  c := text_buf^[(i + k) AND PRED(N)];
  787.            c2 := Lo(c);
  788.                  PutBytes(c2,1,Put);
  789.                  text_buf^[r] := c;
  790.            INC(r);
  791.                  r := r AND PRED(N);
  792.                  INC(count);
  793.          END;  { for }
  794.        END;  { if c < 256 }
  795.      END; {endwhile count < textsize }
  796.    finally
  797.      ENDLZH;
  798.    end;
  799. end;
  800. // Return as many bytes to the LZH compression buffer as requested.
  801. procedure TLZH.GetBlockStream(var DTA; NBytes: Word; var Bytes_Got: Word);
  802. begin
  803.      //copy from stream into lzh compression buffer
  804.      Bytes_Got := NBytes;
  805.      if (StreamIn.Size - StreamIn.Position) < NBytes then
  806.         Bytes_Got := StreamIn.Size - StreamIn.Position;
  807.      StreamIn.ReadBuffer(DTA, Bytes_Got);
  808. end;
  809. procedure TLZH.PutBlockStream(var DTA; NBytes: Word; var Bytes_Got: Word);
  810. begin
  811.      //write from lzh decompression buffer to stream
  812.      Bytes_Got := NBytes;
  813.      StreamOut.WriteBuffer(DTA, Bytes_Got);
  814. end;
  815. END.