Subversion Repositories decoder

Rev

Blame | Last modification | View Log | RSS feed

  1. {Copyright:      Hagen Reddmann HaReddmann at T-Online dot de
  2.  Author:         Hagen Reddmann
  3.                  public domain, this Copyright must be included unchanged
  4.  known Problems: none
  5.  Version:        5.1,  Part I from Delphi Encryption Compendium  ( DEC Part I)
  6.                  Delphi 5
  7.  Description:    very small and effizient LHSS compression
  8.                  with RC4 like encryption and 32 Bit Checksum
  9.  Remarks:        LHEncodeBuffer() and LHDecodeBuffer() parameter out Data: Pointer
  10.                  MUST be released with FreeMem(Data) by the caller !
  11.                  The interface here works only on one linear chunk of input and
  12.                  process this in one single step. But processing of sequential
  13.                  chunks are possible with LHDeflate() and LHInflate(). Look into
  14.                  LHEncode() and LHDecode() to see some right initialization.
  15.                  Without Encryption the minimal compressable input should be > 10 Bytes.
  16.                  With Encryption the minimal compressable input should be > 13 Bytes.
  17.                  Below these limits the output is larger as the input.
  18.  
  19.  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
  20.  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
  23.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  26.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  27.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  28.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  29.  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. }
  31. unit LHSZ;
  32. {$D-,L-,Y-,C-,O+}
  33.  
  34. {$DEFINE LHEncode}  // include compression code
  35. {$DEFINE LHDecode}  // include decompression code
  36. {$DEFINE LHCrypt}   // include encryption code
  37.  
  38. interface
  39.  
  40. const
  41.   LH_ErrProtected   = -9;  // compressed Data are Password protected
  42.   LH_ErrPassword    = -8;  // bad Password in Decoding
  43.   LH_ErrCRC         = -7;  // bad CRC or decompressed Data detected ( Decode only)
  44.   LH_ErrInflate     = -6;  // error in decode
  45.   LH_ErrWrite       = -5;  // write error in Method WriteProc
  46.   LH_ErrRead        = -4;  // read error in Method RreadProc
  47.   LH_ErrInit        = -3;  // error in initialization phase
  48.   LH_ErrAlloc       = -2;  // can't allocated memory
  49.   LH_ErrGeneric     = -1;  // unspecific error
  50.  
  51.   LH_Ready          =  0;  // all ok
  52.  
  53. // Compression Mode Flags
  54.   LH_TypeMask       = $FF00;
  55.   LH_ModeMask       = $00FF;
  56.  
  57.   LH_Auto           = $0000;
  58.  
  59. // mode flags
  60.   LH_Fastest        = $0001;
  61.   LH_Fast           = $0020;
  62.   LH_Normal         = $0040;
  63.   LH_High           = $0080;
  64.   LH_Max            = $00FF;
  65.  
  66. // type flags
  67.   LH_Text           = $0100;
  68.   LH_Binary         = $0200;
  69.   LH_Huffman        = $0400;
  70.  
  71.  
  72. type
  73.   TReadProc  = function(var Buffer; Count: Integer): Integer of object;
  74.   TWriteProc = function(const Buffer; Count: Integer): Integer of object;
  75.  
  76. {$IFDEF LHEncode}
  77. function LHEncode(const Password: String; ReadProc: TReadProc; WriteProc: TWriteProc; Size, Mode: Integer): Integer;
  78. function LHEncodeBuffer(const Password: String; const Buffer; BufferSize: Integer; out Data: Pointer): Integer;
  79. {$ENDIF}
  80.  
  81. {$IFDEF LHDecode}
  82. function LHDecode(const Password: String; ReadProc: TReadProc; WriteProc: TWriteProc; Size: Integer): Integer;
  83. function LHDecodeBuffer(const Password: String; const Buffer; BufferSize: Integer; out Data: Pointer): Integer;
  84. {$ENDIF}
  85.  
  86. function LHCheck(Code: Integer): Integer; // raise exception if code is a error
  87.  
  88. implementation
  89.  
  90. uses SysUtils;
  91. { generated Codesizes with D3, only LHEncode, LHDecode are used, Bufferprocs ignored
  92.   $DEFINES                         size in bytes
  93.     LHEncode                          3.640
  94.     LHEncode, LHCrypt                 4.256
  95.  
  96.     LHDecode                          2.404
  97.     LHDecode, LHCrypt                 2.968
  98.  
  99.     LHEncode, LHDecode                5.148
  100.     LHEncode, LHDecode, LHCrypt       6.104
  101.  
  102.   Datesizes are allways 0
  103. }
  104. {$ALIGN ON}
  105. {$IFOPT O+}
  106.   {$DEFINE UseASM}
  107. {$ENDIF}
  108.  
  109. const
  110.   LH_MinCopy        =       2;   { don't modify, except you increase}
  111.   LH_MaxCopy        =     257;   { should be a power of two +1}
  112.   LH_CodesPerRange  =   LH_MaxCopy - LH_MinCopy +1;
  113.  
  114.   LH_nil            =      -1;           { End of linked list marker}
  115.   LH_HashBits       =      12;           { optimal }
  116.   LH_HashSize       = 1 shl LH_HashBits; { Number of entries in hash table, should be }
  117.   LH_HashMask       = LH_HashSize -1;    { Mask for hash key wrap }
  118.  
  119. { Adaptive Huffman variables }
  120.  
  121.   LH_CodeBits       =      32;
  122.  
  123.   LH_CopyRanges     =      16;
  124. //  (0, 2, 6, 14, 30, 62, 126, 254, 510, 1022, 2046, 4094, 8190, 16382, 32766, 65534, 131070, 262142, 524286);
  125. // stored dynamicaly in TLHData.Range, so we need NO Datasegement for LHSZ
  126.  
  127.   LH_MaxSize        = 131070 + LH_MaxCopy;  // dependend from LH_CopyRange
  128.  
  129.   LH_Special        =     256;          { Command code, subcommands can be 0-255 }
  130.   LH_SpecialINC     =       0;          { Subcommand, copy Range increment}
  131.   LH_SpecialEOF     =       1;          { Subcommand, Terminate}
  132.   LH_SpecialCRC     =       2;          { Subcommand, Checksum}
  133.  
  134.   LH_SpecialBITS    =       3;
  135.  
  136.  
  137.   LH_FirstCode      =     257;          { First code for COPYING lengths }
  138.   LH_MaxChar        = LH_FirstCode + LH_CopyRanges * LH_CodesPerRange -1;
  139.   LH_MaxChar2       = LH_MaxChar * 2 +1;
  140.   LH_Root           =       1;
  141.   LH_BufSize        =    1024 * 4; { buffer size, must be a multiply of Sizeof(Integer) }
  142.  
  143. // LHState
  144.   LH_Init           =  1;
  145.   LH_Working        =  2;
  146.   LH_Finish         =  3;
  147.  
  148.  
  149. type
  150.   PInteger = ^Integer;
  151.   PByte    = ^Byte;
  152.   PWord    = ^Word;
  153.  
  154.   PLHData = ^TLHData;
  155.   TLHData = record
  156.     Data: array[0..LH_BufSize -1] of Byte;   // IN for Deflate, OUT for Inflate
  157.     Code: array[0..LH_BufSize -1] of Byte;   // OUT for Deflate, IN for Inflate
  158.  
  159.     CRCTable: array[0..255] of Integer;
  160.     CRC: Integer;
  161. // from here
  162.     TextPos: Integer;
  163.  
  164.     DataPos: Integer;
  165.     DataBytes: Integer;
  166.     DataSize: Integer;
  167.  
  168.     CodeBits: Integer;
  169.     CodeBitsCount: Integer;
  170.     CodePos: Integer;
  171.     CodeBytes: Integer;
  172.     CodeSize: Integer;
  173.  
  174.     Flag: Integer;
  175.     Text: array[0..LH_MaxSize + LH_MaxCopy] of Byte;
  176. // upto here, don't change this order, we fillout these with zero in one step !
  177.  
  178.     State: Integer; // current State
  179.     InputSize: Integer;
  180.     Read: TReadProc;
  181.     Write: TWriteProc;
  182.  
  183. { Huffman tree }
  184.     Range: array[0..LH_CopyRanges] of Integer;
  185.     RangeCopy: Integer;
  186.     RangeMax: Integer;
  187.  
  188.     FreqCum: Integer;
  189.     FreqReset: Integer;
  190.     Left: array[LH_Root..LH_MaxChar] of Word;
  191.     Right: array[LH_Root..LH_MaxChar] of Word;
  192.     Parent: array[LH_Root..LH_MaxChar2] of Word;
  193.     Freq: array[LH_Root..LH_MaxChar2] of Word;
  194.     Chars: array[Byte] of Integer;
  195.  
  196. {encryption, modified RC4 with 8Bit CBC Freedback and Datadependend SBox shuffeling}
  197. {$IFDEF LHCrypt}
  198.     PC4_T: array[0..255] of Byte;
  199.     PC4_P: Integer;
  200.     PC4_I: Byte;
  201.     PC4_J: Byte;
  202.     PC4_F: Byte;
  203. {$ENDIF}
  204.  
  205. {LZSS data, beginning of deflate only datas}
  206.     Head: array[0..LH_HashSize -1] of Integer;
  207.     Tail: array[0..LH_HashSize -1] of Integer;
  208.     Next: array[0..LH_MaxSize  -1] of Integer;
  209.     Prev: array[0..LH_MaxSize  -1] of Integer;
  210.  
  211.     Mode: Integer; // LH_Mode Flags
  212.     ResetPos: Integer;
  213.     SearchMax: Integer;
  214.     SearchDepth: Integer;
  215.     TextLen: Integer;
  216.     RangeDist: Integer;
  217.     RangeLimit: Integer;
  218. //    LastBytes: Integer;
  219. //    OverBytes: Integer;
  220.  
  221.     CurPos: Integer;
  222.     NewPos: Integer;
  223.     Distance: Integer;
  224.   end;
  225.  
  226. {$IFDEF LHDecode}
  227.   PLHInflate = ^TLHInflate;
  228.   TLHInflate = record
  229.     Data: array[0..LH_BufSize -1] of Byte;   // IN for Deflate, OUT for Inflate
  230.     Code: array[0..LH_BufSize -1] of Byte;   // OUT for Deflate, IN for Inflate
  231.  
  232.     CRCTable: array[0..255] of Integer;
  233.     CRC: Integer;
  234. // from here
  235.     TextPos: Integer;
  236.  
  237.     DataPos: Integer;
  238.     DataBytes: Integer;
  239.     DataSize: Integer;
  240.  
  241.     CodeBits: Integer;
  242.     CodeBitsCount: Integer;
  243.     CodePos: Integer;
  244.     CodeBytes: Integer;
  245.     CodeSize: Integer;
  246.  
  247.     Flag: Integer;
  248.     Text: array[0..LH_MaxSize + LH_MaxCopy] of Byte;
  249. // upto here, don't change this order, we fillout these with zero in one step !
  250.  
  251.     State: Integer; // current State
  252.     InputSize: Integer;
  253.     Read: TReadProc;
  254.     Write: TWriteProc;
  255.  
  256. { Huffman tree }
  257.     Range: array[0..LH_CopyRanges] of Integer;
  258.     RangeCopy: Integer;
  259.     RangeMax: Integer;
  260.  
  261.     FreqCum: Integer;
  262.     FreqReset: Integer;
  263.  
  264.     Left: array[LH_Root..LH_MaxChar] of Word;
  265.     Right: array[LH_Root..LH_MaxChar] of Word;
  266.     Parent: array[LH_Root..LH_MaxChar2] of Word;
  267.     Freq: array[LH_Root..LH_MaxChar2] of Word;
  268.  
  269. {encryption, modified RC4 with 8Bit CBC Freedback and Datadependend SBox shuffeling}
  270. {$IFDEF LHCrypt}
  271.     PC4_T: array[0..255] of Byte;
  272.     PC4_P: Integer;
  273.     PC4_I: Byte;
  274.     PC4_J: Byte;
  275.     PC4_F: Byte;
  276. {$ENDIF}
  277.   end;
  278. {$ENDIF}
  279.  
  280. // procedures for deflation and inflation
  281.  
  282. procedure LHFill(Buffer: Pointer; Size: Integer); assembler; register;
  283. asm
  284.          PUSH  EDI
  285.          MOV   EDI,EAX
  286.          MOV   ECX,EDX
  287.          SHR   ECX,2
  288.          XOR   EAX,EAX
  289.          REP   STOSD
  290.          POP   EDI
  291. end;
  292.  
  293. procedure LHInitCRC(LH: PLHData);
  294. {$IFDEF UseASM}
  295. asm
  296.          PUSH  EBX
  297.          MOV   [EAX].TLHData.CRC,0FFFFFFFFh
  298.          ADD   EAX,OFFSET TLHData.CRCTable
  299.          MOV   ECX,255
  300. @@1:     MOV   EDX,ECX
  301.          MOV   EBX,8
  302. @@2:     SHR   EDX,1
  303.          JNC   @@3
  304.          XOR   EDX,0EDB88320h
  305. @@3:     DEC   EBX
  306.          JNZ   @@2
  307.          MOV   [EAX + ECX * 4],EDX
  308.          DEC   ECX
  309.          JNL   @@1
  310.          POP   EBX
  311. end;
  312. {$ELSE}
  313. var
  314.   I,J,V: Integer;
  315. begin
  316.   for I := 0 to 255 do
  317.   begin
  318.     V := I;
  319.     for J := 0 to 7 do
  320.       if V and 1 <> 0 then V := (V shr 1) xor Integer($EDB88320)
  321.         else V := V shr 1;
  322.     LH.CRCTable[I] := V;
  323.   end;
  324.   LH.CRC := Integer($FFFFFFFF);
  325. end;
  326. {$ENDIF}
  327.  
  328. function LHUpdateCRC(LH: PLHData; const Buffer; Size: Integer): Integer;
  329. {$IFDEF UseASM}
  330. asm
  331.          PUSH  EBX
  332.          PUSH  EDI
  333.          XOR   EBX,EBX
  334.          LEA   EDI,[EAX].TLHData.CRCTable
  335.          MOV   EAX,[EAX].TLHData.CRC
  336.          DEC   ECX
  337.          JLE   @@2
  338.  
  339. @@1:     MOV   EBX,[EDX]
  340.          INC   EDX
  341.          XOR   EBX,EAX
  342.          SHR   EAX,8
  343.          MOVZX EBX,BL
  344.          XOR   EAX,[EDI + EBX * 4]
  345.          DEC   ECX
  346.          JNL   @@1
  347.  
  348. @@2:     POP   EDI
  349.          POP   EBX
  350. end;
  351. {$ELSE}
  352. var
  353.   P: ^Byte;
  354.   C: Integer;
  355. begin
  356.   P := @Buffer;
  357.   C := LH.CRC;
  358.   while Size > 0 do
  359.   begin
  360.     Dec(Size);
  361.     C := C shr 8 xor LH.CRCTable[(C xor P^) and $FF];
  362.     Inc(P);
  363.   end;
  364.   Result := C;
  365. end;
  366. {$ENDIF}
  367.  
  368. {$IFDEF LHCrypt}
  369. procedure LHInitCrypt(LH: PLHData; const Password: String);
  370. var
  371.   I,S,J: Integer;
  372.   K: array[0..255] of Byte;
  373. begin
  374.   LH.PC4_P := 0;
  375.   LH.PC4_I := 0;
  376.   LH.PC4_J := 0;
  377.   S := Length(Password);
  378.   if S = 0 then Exit;
  379.   J := 0;
  380.   for I := 0 to 255 do
  381.   begin
  382.     LH.PC4_T[I] := I;
  383.     K[I] := Byte(Password[I mod S +1]);
  384.     J := (J + K[I] * 257) mod MaxInt +1;
  385.   end;
  386.   LH.PC4_P := J;
  387.   LH.PC4_F := J shr 8;
  388.   for I := 0 to 255 do
  389.   begin
  390.     J := (J + LH.PC4_T[I] + K[I]) and $FF;
  391.     S := LH.PC4_T[I];
  392.     LH.PC4_T[I] := LH.PC4_T[J];
  393.     LH.PC4_T[J] := S;
  394.   end;
  395. end;
  396. {$ENDIF}
  397. // Huffman support
  398.  
  399. procedure LHInitHuffman(LH: PLHData);
  400. var  { Initialize Huffman frequency tree }
  401.   I: Integer;
  402. begin
  403.   LH.Range[0] := 0;
  404.   for I := 1 to High(LH.Range) do
  405.     LH.Range[I] := LH.Range[I -1] * 2 + 2;
  406.   LH.FreqCum := LH_MaxChar2;
  407.   LH.FreqReset := 20000;
  408.   LHFill(@LH.Chars, SizeOf(LH.Chars));
  409.   for I := LH_Root to LH_MaxChar2 do
  410.   begin
  411.     LH.Parent[I] := I shr 1;
  412.     LH.Freq[I] := 1;
  413.   end;
  414.   for I := LH_Root to LH_MaxChar do
  415.   begin
  416.     LH.Left[I] := I * 2;
  417.     LH.Right[I] := I * 2 + 1;
  418.   end;
  419. end;
  420.  
  421. procedure LHResetFrequency(LH: PLHData);
  422. {$IFDEF UseASM}
  423. asm
  424.          PUSH  EBX
  425.          PUSH  EDI
  426.          PUSH  ESI
  427.  
  428.          LEA   ESI,[EAX].TLHData.Freq
  429.          MOV   ECX,LH_MaxChar2 shr 1
  430.          XOR   EDI,EDI
  431.  
  432. @@1:     MOV   EAX,[ESI]
  433.  
  434.          ADD   EAX,000010001h
  435.          AND   EAX,0FFFEFFFEh
  436.          SHR   EAX,1
  437.          MOV   EDX,EAX
  438.          MOV   [ESI],EAX
  439.          SHR   EDX,16
  440.          MOVZX EAX,AX
  441.          ADD   EDI,EDX
  442.          ADD   EDI,EAX
  443.  
  444.          DEC   ECX
  445.          LEA   ESI,[ESI + 4]
  446.          JNZ   @@1
  447.  
  448. // process last Word
  449.          MOVZX EAX,Word Ptr [ESI]
  450.          ADD   EAX,1
  451.          AND   EAX,0FFFEh
  452.          SHR   EAX,1
  453.          MOV   [ESI],AX
  454.          ADD   EDI,EAX
  455.          MOV   [EBX].TLHData.FreqCum,EDI
  456.  
  457.          POP   ESI
  458.          POP   EDI
  459.          POP   EBX
  460. end;
  461. {$ELSE}
  462. var
  463.   I: Integer;
  464. begin
  465.   LH.FreqCum := 0;
  466.   for I := LH_Root to LH_MaxChar2 do
  467.   begin
  468.     LH.Freq[I] := (LH.Freq[I] + 1) shr 1;
  469.     Inc(LH.FreqCum, LH.Freq[I]);
  470.   end;
  471. end;
  472. {$ENDIF}
  473.  
  474. procedure LHUpdateModel(LH: PLHData; Code: Integer);
  475.  
  476.   procedure LHUpdateFrequency(LH: PLHData; A,B: Integer);
  477.   begin { Update frequency counts from leaf to root }
  478.     repeat
  479.       B := LH.Freq[A] + LH.Freq[B];
  480.       A := LH.Parent[A];
  481.       Inc(LH.FreqCum, B - LH.Freq[A]);
  482.       LH.Freq[A] := B;
  483.       if A <> LH_Root then
  484.       begin
  485.         B := LH.Parent[A];
  486.         if LH.Left[B] <> A then B := LH.Left[B] else B := LH.Right[B];
  487.       end else Break;
  488.     until False;
  489.   end;
  490.  
  491. var { Update Huffman model for each character code }
  492.   A, B, C, X, Y: Integer;
  493. begin
  494.   Inc(LH.Chars[Code mod 256]);
  495.   if LH.FreqCum > LH.FreqReset then
  496.   begin
  497.     C := 0;
  498.     for X := 0 to 255 do
  499.     begin
  500.       if LH.Chars[X] > 0 then Inc(C);
  501.       LH.Chars[X] := 0;//LH.Chars[X] shr 3;
  502.     end;
  503.     if (C < 64) and (LH.FreqReset > 14000) then
  504.       Dec(LH.FreqReset, 1000)
  505.     else
  506.       if (C > 128) and (LH.FreqReset < 20000) then
  507.         Inc(LH.FreqReset, 1000);
  508.     LHResetFrequency(LH);
  509.   end;
  510.   A := Code + LH.RangeMax;
  511.   Inc(LH.Freq[A]);
  512.   Inc(LH.FreqCum);
  513.   X := LH.Parent[A];
  514.   if X <> LH_Root then
  515.   begin
  516.     if LH.Left[X] <> A then LHUpdateFrequency(LH, A, LH.Left[X])
  517.       else LHUpdateFrequency(LH, A, LH.Right[X]);
  518.     repeat
  519.       Y := LH.Parent[X];
  520.       if LH.Left[Y] <> X then B := LH.Left[Y] else B := LH.Right[Y];
  521.       if LH.Freq[A] >= LH.Freq[B] then
  522.       begin
  523.         LH.Parent[A] := Y;
  524.         LH.Parent[B] := X;
  525.         if LH.Left[Y] <> X then LH.Left[Y] := A else LH.Right[Y] := A;
  526.         C := LH.Left[X];
  527.         if C = A then
  528.         begin
  529.           LH.Left[X] := B;
  530.           C := LH.Right[X];
  531.         end else LH.Right[X] := B;
  532.         LHUpdateFrequency(LH, B, C);
  533.         A := B;
  534.       end;
  535.       A := LH.Parent[A];
  536.       X := LH.Parent[A];
  537.     until X = LH_Root;
  538.   end;
  539. end;
  540.  
  541. // deflation
  542. {$IFDEF LHEncode}
  543. procedure LHDeflate(LH: PLHData);
  544. const
  545.   LH_Found    = 1;
  546.   LH_Full     = 2;
  547.   LH_First    = 4;
  548.  
  549.   LH_ModeHuff = Integer($80000000);
  550.   LH_ModeBIN  = $40000000;
  551.  
  552.   function LHHash(LH: PLHData; Index: Integer): Integer;
  553. {$IFDEF UseASM}
  554.   asm
  555.          MOV    EAX,DWord Ptr [EAX].TLHData.Text[EDX]  // Text use overestimated Ringbuffer
  556.          AND    EAX,0FFFFFFh
  557.          MOV    ECX,EAX
  558.          SHR    ECX,9
  559.          XOR    EAX,ECX
  560.          SHR    ECX,5
  561.          XOR    EAX,ECX
  562.          AND    EAX,LH_HashMask
  563.   end;
  564. {$ELSE}
  565.   var
  566.     I: Integer;
  567.   begin
  568.     I := PInteger(@LH.Text[Index])^ and $FFFFFF;
  569.     Result := (I xor (I shr 9) xor (I shr 14)) and LH_HashMask;
  570.   end;
  571. {$ENDIF}
  572.  
  573.   procedure LHInitLZSS(LH: PLHData);
  574. {$IFDEF UseASM}
  575.   asm
  576.          PUSH   EBX
  577.          PUSH   EDI
  578.          MOV    EBX,EAX
  579.  
  580.          XOR    EAX,EAX
  581.          LEA    EDI,[EBX].TLHData.DataPos
  582.          MOV    [EBX].TLHData.TextLen,EAX
  583.          MOV    [EBX].TLHData.ResetPos,EAX
  584.          MOV    ECX,10 + LH_MaxSize shr 2
  585.          REP    STOSD
  586.  
  587.          MOV    EAX,LH_MinCopy
  588.          MOV    [EBX].TLHData.TextPos,EAX
  589.          MOV    [EBX].TLHData.NewPos,EAX
  590.  
  591.          MOV    [EBX].TLHData.CodeBitsCount,LH_CodeBits
  592.  
  593.          LEA    EDI,[EBX].TLHData.Head
  594.          MOV    EAX,LH_nil
  595.          MOV    ECX,LH_HashSize
  596.          REP    STOSD
  597.  
  598.          POP    EDI
  599.          POP    EBX
  600.   end;
  601. {$ELSE}
  602.   var
  603.     I: Integer;
  604.   begin
  605.     with LH^ do
  606.     begin
  607.       LHFill(@LH.DataPos, LH_MaxSize + 10 * 4);
  608.       TextLen := 0;
  609.       ResetPos := 0;
  610.       CodeBitsCount := LH_CodeBits;
  611.       TextPos := LH_MinCopy;
  612.       NewPos := LH_MinCopy;
  613.       for I := Low(Head) to High(Head) do Head[I] := LH_nil;
  614.     end;
  615.   end;
  616. {$ENDIF}
  617.  
  618.   procedure LHInsertNode(LH: PLHData; N: Integer);
  619. {$IFDEF UseASM}  { insert node to head of list }
  620.   asm
  621.          PUSH   EBX
  622.  
  623.          MOV    EBX,EAX
  624.          CALL   LHHash               // EAX = Key
  625.  
  626.          MOV    ECX,DWord Ptr [EBX].TLHData.Head[EAX * 4]  // ECX = T
  627.          MOV    DWord Ptr [EBX].TLHData.Head[EAX * 4],EDX
  628.          MOV    DWord Ptr [EBX].TLHData.Prev[EDX * 4],LH_nil
  629.          CMP    ECX,LH_nil
  630.          JNZ    @@1
  631.  
  632.          MOV    DWord Ptr [EBX].TLHData.Tail[EAX * 4],EDX
  633.          MOV    DWord Ptr [EBX].TLHdata.Next[EDX * 4],LH_nil
  634.          JMP    @@2
  635.  
  636. @@1:     MOV    DWord Ptr [EBX].TLHData.Prev[ECX * 4],EDX
  637.          MOV    DWord Ptr [EBX].TLHData.Next[EDX * 4],ECX
  638.  
  639. @@2:     POP    EBX
  640.   end;
  641. {$ELSE}
  642.   var
  643.     Key,T: Integer;
  644.   begin
  645.     Key := LHHash(LH, N);
  646.     with LH^ do
  647.     begin
  648.       T := Head[Key];
  649.       Head[Key] := N;
  650.       Prev[N] := LH_nil;
  651.       if T = LH_nil then
  652.       begin
  653.         Tail[Key] := N;
  654.         Next[N] := LH_nil;
  655.       end else
  656.       begin
  657.         Next[N] := T;
  658.         Prev[T] := N;
  659.       end;
  660.     end;
  661.   end;
  662. {$ENDIF}
  663.  
  664.   procedure LHDeleteNode(LH: PLHData; N: Integer);
  665. {$IFDEF UseASM} { Delete node from tail of list }
  666.   asm
  667.          PUSH   EBX
  668.          MOV    EBX,EAX
  669.          CALL   LHHash               // EAX = Key
  670.  
  671.          MOV    ECX,DWord Ptr [EBX].TLHData.Tail[EAX * 4]
  672.          CMP    ECX,LH_Nil
  673.          JE     @@0
  674.          CMP    ECX,DWord Ptr [EBX].TLHData.Head[EAX * 4]
  675.          JNE    @@1
  676. @@0:     MOV    DWord Ptr [EBX].TLHData.Head[EAX * 4],LH_nil
  677.          JMP    @@2
  678.  
  679. @@1:     MOV    ECX,DWord Ptr [EBX].TLHData.Prev[ECX * 4]
  680.          MOV    DWord Ptr [EBX].TLHData.Tail[EAX * 4],ECX
  681.          CMP    ECX,LH_nil
  682.          JE     @@2
  683.          MOV    DWord Ptr [EBX].TLHData.Next[ECX * 4],LH_nil
  684.  
  685. @@2:     POP    EBX
  686.   end;
  687. {$ELSE}
  688.   var
  689.     Key, T: Integer;
  690.   begin
  691.     Key := LHHash(LH, N);
  692.     with LH^ do
  693.     begin
  694.       T := Tail[Key];
  695.       if (T <> LH_nil) and (Head[Key] <> T) then
  696.       begin
  697.         T := Prev[T];
  698.         Tail[Key] := T;
  699.         if T <> LH_nil then Next[T] := LH_nil;
  700.       end else Head[Key] := LH_nil;
  701.     end;
  702.   end;
  703. {$ENDIF}
  704.  
  705.   procedure LHUpdateRange(LH: PLHData); forward;
  706.  
  707.   function LHMatch(LH: PLHData; SearchDepth: Boolean): Integer;
  708. { Find longest string matching lookahead buffer string }
  709.  
  710.     function LHCompare(LH: PLHData; N, K: Integer): Integer;
  711.     var
  712.       I: Integer;
  713.     begin
  714.       Result := 0;
  715.       I := N;
  716.       while (K <> N) and (I <> LH.TextPos) and (LH.Text[I] = LH.Text[K]) do
  717.       begin
  718.         Inc(I);
  719.         Inc(K);
  720.         Inc(Result);
  721.         if Result >= LH_MaxCopy then Exit;
  722.       end;
  723.     end;
  724.  
  725.   var
  726.     N,K,L,D,C,Depth: Integer;
  727.   begin
  728.     Result := 0;
  729.     N := LH.NewPos;
  730.     if SearchDepth then
  731.     begin
  732.       Depth := LH.SearchDepth;
  733.       if Depth <= 0 then Exit;
  734.       Inc(N);
  735.       if N >= LH_MaxSize then N := 0;
  736.     end else
  737.     begin
  738.       Depth := LH.SearchMax;
  739.       LH.Distance := 0;
  740.     end;
  741.  
  742.     K := LH.Head[LHHash(LH, N)];
  743.     if K = LH_nil then Exit;
  744.  
  745.     C := LH.Text[N];
  746.     repeat
  747.       if C = LH.Text[K + Result] then
  748.       begin
  749.         L := LHCompare(LH, N, K);
  750.         if (L >= LH_MinCopy) and (L > Result) then
  751.         begin
  752.           D := N - K - L;
  753.           if D < 0 then Inc(D, LH_MaxSize);
  754.           if not SearchDepth then LH.Distance := D;
  755.           Result := L;
  756.           if L >= LH_MaxCopy then Exit;
  757.           C := LH.Text[L + N];
  758.         end;
  759.       end;
  760.       Dec(Depth);
  761.       if Depth <= 0 then Exit;
  762.       K := LH.Next[K];
  763.     until K = LH_nil;
  764.   end;
  765.  
  766. {$IFDEF LHCrypt}
  767.   procedure LHCrypt(LH: PLHData; Size: Integer);
  768.   var
  769.     S: Byte;
  770.     B: PByte;
  771.   begin
  772.     B := @LH.Code;
  773.     if LH.Flag and LH_First = 0 then
  774.     begin
  775.       Inc(B);
  776.       Dec(Size);
  777.       LH.Flag := LH.Flag or LH_First;
  778.     end;
  779.     while Size > 0 do
  780.     begin
  781.       Dec(Size);
  782.       Inc(LH.PC4_I);
  783.       S := LH.PC4_T[LH.PC4_I];
  784.       Inc(LH.PC4_J, S);
  785.       LH.PC4_T[LH.PC4_I] := LH.PC4_T[LH.PC4_J] xor LH.PC4_F;
  786.       LH.PC4_T[LH.PC4_J] := S - LH.PC4_F;
  787.       B^ := (B^ + LH.PC4_F) xor LH.PC4_T[(LH.PC4_T[LH.PC4_I] + S) and $FF];
  788.       LH.PC4_F := B^;
  789.       Inc(B);
  790.     end;
  791.   end;
  792. {$ENDIF}
  793.   function LHWrite(LH: PLHData): Boolean;
  794.   begin
  795.     if LH.State >= LH_Ready then
  796.     begin
  797.       LH.CodeBitsCount := LH_CodeBits;
  798.       PInteger(@LH.Code[LH.CodePos])^ := LH.CodeBits;
  799.       Inc(LH.CodePos, SizeOf(LH.CodeBits));
  800.       Inc(LH.CodeBytes, SizeOf(LH.CodeBits));
  801.       LH.CodeBits := 0;
  802.       if LH.CodePos >= SizeOf(LH.Code) then
  803.       begin
  804. {        if LH.DataBytes - LH.LastBytes < LH.CodePos then
  805.           Inc(LH.OverBytes, LH.CodePos - (LH.DataBytes - LH.LastBytes));
  806.         LH.LastBytes := LH.DataBytes;}
  807. {$IFDEF LHCrypt}
  808.         if LH.PC4_P <> 0 then LHCrypt(LH, LH.CodePos);
  809. {$ENDIF}
  810.         if LH.Write(LH.Code, LH.CodePos) <> LH.CodePos then
  811.           LH.State := LH_ErrWrite;
  812.         LH.CodePos := 0;
  813.       end;
  814.     end;
  815.     Result := LH.State >= LH_Ready;
  816.   end;
  817.  
  818.   procedure LHWriteCode(LH: PLHData; Value, Bits: Integer);
  819. {$IFDEF UseASM}
  820.   asm
  821.          PUSH  EBX
  822.          PUSH  EDI
  823.          MOV   EBX,EAX
  824.          MOV   EDI,ECX
  825.          MOV   EAX,[EBX].TLHData.CodeBits
  826.          MOV   ECX,[EBX].TLHData.CodeBitsCount
  827.  
  828. @@1:     SHR   EDX,1
  829.          RCR   EAX,1
  830.          DEC   ECX
  831.          JZ    @@3
  832. @@2:     DEC   EDI
  833.          JNZ   @@1
  834.          MOV   [EBX].TLHData.CodeBits,EAX
  835.          MOV   [EBX].TLHData.CodeBitsCount,ECX
  836.  
  837.          POP   EDI
  838.          POP   EBX
  839.          RET
  840.  
  841. @@3:     PUSH  EDX
  842.          MOV   [EBX].TLHData.CodeBits,EAX
  843.          MOV   EAX,EBX
  844.          CALL  LHWrite
  845.          MOV   ECX,[EBX].TLHData.CodeBitsCount
  846.          POP   EDX
  847.          JMP   @@2
  848.   end;
  849. {$ELSE}
  850.   begin
  851.     while Bits > 0 do
  852.     begin
  853.       LH.CodeBits := (LH.CodeBits shr 1) or (Value and 1) shl (LH_CodeBits -1);
  854.       Value := Value shr 1;
  855.       Dec(LH.CodeBitsCount);
  856.       if (LH.CodeBitsCount = 0) and not LHWrite(LH) then Exit;
  857.       Dec(Bits);
  858.     end;
  859.   end;
  860. {$ENDIF}
  861.  
  862.   procedure LHCompress(LH: PLHData; Code: Integer);
  863.   var
  864.     A,S,T: Integer;
  865.     K: array[0..63] of Boolean;
  866.   begin
  867.     S := 0;
  868.     A := Code + LH.RangeMax;
  869.     repeat
  870.       T := LH.Parent[A];
  871.       K[S] := LH.Right[T] = A;
  872.       A := T;
  873.       Inc(S);
  874.     until A = LH_Root;
  875.     repeat
  876.       Dec(S);
  877.       LH.CodeBits := LH.CodeBits shr 1 or Byte(K[S]) shl (LH_CodeBits -1);
  878.       Dec(LH.CodeBitsCount);
  879.       if (LH.CodeBitsCount = 0) and not LHWrite(LH) then Exit;
  880.     until S = 0;
  881.     LHUpdateModel(LH, Code);
  882.   end;
  883.  
  884.   procedure LHUpdateRange(LH: PLHData);
  885.   begin
  886.     if LH.RangeCopy < LH_CopyRanges then
  887.     begin
  888.       LHCompress(LH, LH_Special);
  889.       LHWriteCode(LH, LH_SpecialINC, LH_SpecialBITS);
  890.       Inc(LH.RangeCopy);
  891.       LH.RangeMax  := LH_FirstCode + (LH.RangeCopy * LH_CodesPerRange);
  892.       LH.RangeDist := LH.Range[LH.RangeCopy];
  893.     end;
  894.   end;
  895.  
  896.   procedure LHFlush(LH: PLHData);
  897.   var
  898.     I: Integer;
  899.   begin
  900.     if LH.CodeBitsCount > 0 then
  901.     begin
  902.       PInteger(@LH.Code[LH.CodePos])^ := LH.CodeBits shr LH.CodeBitsCount;
  903.       I := (LH_CodeBits + 7 - LH.CodeBitsCount) div 8;
  904.       Inc(LH.CodePos, I);
  905.       Inc(LH.CodeBytes, I);
  906.       LH.CodeBitsCount := LH_CodeBits;
  907.       LH.CodeBits := 0;
  908.     end;
  909.     if LH.CodePos > 0 then
  910.     begin
  911. {$IFDEF LHCrypt}
  912.       if LH.PC4_P <> 0 then LHCrypt(LH, LH.CodePos);
  913. {$ENDIF}
  914.       if LH.Write(LH.Code, LH.CodePos) <> LH.CodePos then
  915.         LH.State := LH_ErrWrite;
  916.     end;
  917.   end;
  918.  
  919.   function LHRead(LH: PLHData): Boolean;
  920.   var
  921.     I: Integer;
  922.   begin
  923.     LH.DataPos := 0;
  924.     I := SizeOf(LH.Data);
  925.     if (LH.InputSize >= 0) and (LH.InputSize < LH.DataSize) then I := LH.InputSize;
  926.     if I > 0 then LH.DataSize := LH.Read(LH.Data, I)
  927.       else LH.DataSize := I;
  928.     if LH.DataSize = 0 then LH.State := LH_Finish else
  929.       if LH.DataSize < 0 then LH.State := LH_ErrRead else
  930.       begin
  931.         if LH.InputSize > 0 then Dec(LH.InputSize, LH.DataSize);
  932.         LH.CRC := LHUpdateCRC(LH, LH.Data, LH.DataSize);
  933.       end;
  934.     Result := LH.State >= LH_Ready;
  935.   end;
  936.  
  937. var
  938.   I, C: Integer;
  939. label
  940.   Skip, Huffman, Finish;
  941. begin
  942.   if LH.State = LH_Init then
  943.   begin
  944.     LHInitCRC(LH);
  945.     LHInitLZSS(LH);
  946.     LHInitHuffman(LH);
  947.  
  948.     LH.RangeCopy  := 12;
  949.     LH.RangeMax   := LH_FirstCode + (LH.RangeCopy * LH_CodesPerRange);
  950.     LH.RangeDist  := LH.Range[LH.RangeCopy];
  951.  
  952.     if not LHRead(LH) or (LH.DataSize <= 0) then
  953.     begin
  954.       LH.State := LH_ErrRead;
  955.       Exit;
  956.     end;
  957.     LH.State := LH_Working;
  958.  
  959. {$IFDEF LHCrypt}
  960.     if LH.PC4_P <> 0 then
  961.     begin
  962.       I := RandSeed; Randomize; C := Random(MaxInt); RandSeed := I;
  963.       for I := 0 to LH.DataSize -1 do
  964.         C := (C + LH.Data[I] * 257) mod MaxInt +1;
  965.       LHWriteCode(LH, 1, 1);
  966.       LHWriteCode(LH, C, 8);
  967.       LHWriteCode(LH, LH.PC4_P xor C, 8);
  968.     end else LHWriteCode(LH, 0, 1);
  969. {$ELSE}
  970.     LHWriteCode(LH, 0, 1);
  971. {$ENDIF}
  972.   { Compress first few characters using Huffman }
  973.     for I := 0 to LH_MinCopy -1 do
  974.     begin
  975.       C := LH.Data[LH.DataPos];
  976.       Inc(LH.DataPos);
  977.       LHCompress(LH, C);
  978.       Inc(LH.DataBytes);
  979.       LH.Text[I] := C;
  980.       if LH.DataPos >= LH.DataSize then
  981.       begin
  982.         if not LHRead(LH) then Exit;
  983.         if LH.State = LH_Finish then goto Finish;
  984.       end;
  985.     end;
  986.  
  987.   { Preload next few characters into lookahead buffer }
  988.     if LH.State = LH_Working then
  989.       for I := 0 to LH_MaxCopy -1 do
  990.       begin
  991.         C := LH.Data[LH.DataPos];
  992.         Inc(LH.DataPos);
  993.         LH.Text[LH.TextPos] := C;
  994.         if LH.TextPos <= LH_MaxCopy then LH.Text[LH_MaxSize + LH.TextPos] := C;
  995.         Inc(LH.TextPos);
  996.         Inc(LH.DataBytes);
  997.         if LH.DataPos >= LH.DataSize then
  998.         begin
  999.           if not LHRead(LH) then Exit;
  1000.           if LH.State = LH_Finish then Break;
  1001.         end;
  1002.       end;
  1003.     if (LH.Mode and LH_Binary <> 0) or (LH.Mode and LH_TypeMask <> LH_Text) then
  1004.     begin
  1005.       C := 0;
  1006.       for I := 0 to LH_MaxCopy + LH_MinCopy do
  1007.         if LH.Text[I] > 0 then Inc(C);
  1008.       if C > 2 then LH.Mode := LH.Mode or LH_ModeBIN;
  1009.     end;
  1010.     if LH.Mode and LH_ModeMask = LH_Max then
  1011.     begin
  1012.       LH.SearchMax   := MaxInt;
  1013.       LH.SearchDepth := MaxInt;
  1014.     end else
  1015.     begin
  1016.       if LH.Mode and LH_ModeMask = LH_Auto then
  1017.       begin
  1018.         LH.SearchMax   := LH_Normal * 4;
  1019.         LH.SearchDepth := LH_Normal * 2;
  1020.       end else
  1021.       begin
  1022.         LH.SearchMax   := (LH.Mode and LH_ModeMask -1) * 4 +2;
  1023.         LH.SearchDepth := (LH.Mode and LH_ModeMask -1) * 2;
  1024.       end;
  1025.       if LH.Mode and LH_ModeBIN = 0 then
  1026.       begin
  1027.         LH.SearchMax   := LH.SearchMax * 3;
  1028.         LH.SearchDepth := LH.SearchDepth * 2;
  1029.       end;
  1030.     end;
  1031.     if LH.Mode and LH_Huffman <> 0 then
  1032.       LH.Mode := LH.Mode or LH_ModeHuff;
  1033.   end else
  1034.     if (LH.State = LH_Working) and (LH.DataSize = 0) and not LHRead(LH) then Exit;
  1035.  
  1036.   if LH.State < LH_Working then Exit;
  1037.  
  1038.   repeat
  1039.     { Update nodes in hash table lists }
  1040.     if LH.Mode and LH_ModeHuff <> 0 then goto Huffman;
  1041.  
  1042.     if LH.Flag and LH_Full <> 0 then LHDeleteNode(LH, LH.TextPos);
  1043.     LHInsertNode(LH, LH.NewPos);
  1044.     if LH.Flag and LH_Found <> 0 then
  1045.     begin
  1046.       Dec(LH.TextLen);
  1047.       if LH.TextLen = 1 then
  1048.         LH.Flag := LH.Flag and not LH_Found;
  1049.     end else
  1050.     begin
  1051.       LH.TextLen := LHMatch(LH, False);
  1052.       if LH.TextLen >= LH_MinCopy then
  1053.       begin
  1054.         C := LHMatch(LH, True);
  1055.         if LH.TextLen >= C then
  1056.         begin
  1057.           if LH.Distance >= LH.RangeDist then
  1058.           begin
  1059.             LHUpdateRange(LH);
  1060.             if LH.Distance >= LH.RangeDist then goto Huffman;
  1061.           end;
  1062.           for C := 0 to LH.RangeCopy -1 do
  1063.             if LH.Distance < LH.Range[C +1] then
  1064.             begin
  1065.               LH.Flag := LH.Flag or LH_Found;
  1066.               LHCompress(LH, LH.TextLen - LH_MinCopy + LH_FirstCode + C * LH_CodesPerRange);
  1067.               LHWriteCode(LH, LH.Distance - LH.Range[C], C +1);
  1068.               if LH.State < LH_Ready then Exit
  1069.                 else goto Skip;
  1070.             end;
  1071.         end;
  1072.       end;
  1073.  
  1074. Huffman:
  1075.       LHCompress(LH, LH.Text[LH.NewPos]);
  1076.     end;
  1077. Skip:
  1078.  
  1079.   { Advance buffer pointers }
  1080.     Inc(LH.NewPos); if LH.NewPos = LH_MaxSize then LH.NewPos := 0;
  1081.     Inc(LH.CurPos); if LH.CurPos = LH_MaxSize then LH.CurPos := 0;
  1082.  
  1083.   { Add next input character to buffer }
  1084.     if LH.DataSize > 0 then
  1085.     begin
  1086.       C := LH.Data[LH.DataPos];
  1087.       Inc(LH.DataPos);
  1088.       if (LH.DataPos >= LH.DataSize) and not LHRead(LH) then Exit;
  1089.       LH.Text[LH.TextPos] := C;
  1090.       if LH.TextPos <= LH_MaxCopy then LH.Text[LH_MaxSize + LH.TextPos] := C;
  1091.       Inc(LH.TextPos);
  1092.  
  1093.       if LH.TextPos = LH_MaxSize then
  1094.       begin
  1095.         LH.TextPos := 0;
  1096.         LH.Flag := LH.Flag or LH_Full;
  1097.       end;
  1098.       Inc(LH.DataBytes);
  1099.     end else
  1100.       if LH.State = LH_Finish then
  1101.       begin
  1102.         if LH.NewPos = LH.TextPos then
  1103.         begin
  1104. Finish:
  1105.           LHCompress(LH, LH_Special);
  1106.           LHWriteCode(LH, LH_SpecialCRC, LH_SpecialBITS);
  1107.           LHWriteCode(LH, not LH.CRC, 32);
  1108.           LHFlush(LH);
  1109.           LH.State := LH_Ready;
  1110.           Break;
  1111.         end;
  1112.       end else Break;
  1113.   until LH.State < LH_Ready;
  1114. end;
  1115.  
  1116. function LHEncode(const Password: String; ReadProc: TReadProc; WriteProc: TWriteProc; Size, Mode: Integer): Integer;
  1117. var
  1118.   LH: PLHData;
  1119. begin
  1120.   try
  1121.     GetMem(LH, SizeOf(TLHData));
  1122.   except
  1123.     Result := LH_ErrAlloc;
  1124.     Exit;
  1125.   end;
  1126.   try
  1127.     LH.State := LH_Init;
  1128.     LH.Mode := Mode;
  1129.     LH.Read := ReadProc;
  1130.     LH.Write := WriteProc;
  1131.     LH.InputSize := Size;
  1132. {$IFDEF LHCrypt}
  1133.     LHInitCrypt(LH, Password);
  1134. {$ENDIF}
  1135.     LHDeflate(LH);
  1136.   finally
  1137.     Result := LH.State;
  1138.     if Result >= LH_Ready then Result := LH.CodeBytes;
  1139.     LHFill(LH, SizeOf(TLHData));
  1140.     ReallocMem(LH, 0);
  1141.   end;
  1142. end;
  1143. {$ENDIF}
  1144.  
  1145. {$IFDEF LHDecode}
  1146. procedure LHInflate(LH: PLHData);
  1147. const
  1148.   LH_First = 4;
  1149.  
  1150. {$IFDEF LHCrypt}
  1151.   procedure LHCrypt(LH: PLHData; Size: Integer);
  1152.   var
  1153.     S,F: Byte;
  1154.     B: PByte;
  1155.   begin
  1156.     B := @LH.Code;
  1157.     if LH.Flag and LH_First = 0 then
  1158.     begin
  1159.       LH.Flag := LH.Flag or LH_First;
  1160.       if B^ and 1 = 0 then // test if data are encryted
  1161.       begin
  1162.         LH.PC4_P := 0;     // no, deactivate encryption
  1163.         LHFill(@LH.PC4_T, SizeOf(LH.PC4_T));
  1164.         Exit;
  1165.       end;
  1166.       Inc(B);
  1167.       Dec(Size);
  1168.     end;
  1169.     while Size > 0 do
  1170.     begin
  1171.       Dec(Size);
  1172.       Inc(LH.PC4_I);
  1173.       S := LH.PC4_T[LH.PC4_I];
  1174.       Inc(LH.PC4_J, S);
  1175.       LH.PC4_T[LH.PC4_I] := LH.PC4_T[LH.PC4_J] xor LH.PC4_F;
  1176.       LH.PC4_T[LH.PC4_J] := S - LH.PC4_F;
  1177.       F := B^;
  1178.       B^ := B^ xor LH.PC4_T[(LH.PC4_T[LH.PC4_I] + S) and $FF] - LH.PC4_F;
  1179.       LH.PC4_F := F;
  1180.       Inc(B);
  1181.     end;
  1182.   end;
  1183. {$ENDIF}
  1184.  
  1185.   function LHRead(LH: PLHData): Integer;
  1186.   var
  1187.     I: Integer;
  1188.   begin
  1189.     if LH.CodePos >= LH.CodeSize then
  1190.     begin
  1191.       LH.CodePos := 0;
  1192.       LH.CodeSize := SizeOf(LH.Code);
  1193.       if (LH.InputSize > 0) and (LH.CodeSize > LH.InputSize) then
  1194.         LH.CodeSize := LH.InputSize;
  1195.       if LH.CodeSize > 0 then
  1196.         LH.CodeSize := LH.Read(LH.Code, LH.CodeSize);
  1197.       if LH.CodeSize = 0 then LH.State := LH_Finish else
  1198.         if LH.CodeSize < 0 then
  1199.         begin
  1200.           LH.State := LH_ErrRead;
  1201.           Result := LH.State;
  1202.           Exit;
  1203.         end else
  1204.         begin
  1205.           if LH.InputSize > 0 then Dec(LH.InputSize, LH.CodeSize);
  1206.           I := LH.CodeSize;
  1207.           while I mod 4 <> 0 do
  1208.           begin
  1209.             LH.Code[I] := 0;
  1210.             Inc(I);
  1211.           end;
  1212. {$IFDEF LHCrypt}
  1213.           if LH.PC4_P <> 0 then LHCrypt(LH, LH.CodeSize);
  1214. {$ENDIF}
  1215.         end;
  1216.     end;
  1217.     LH.CodeBits := PInteger(@LH.Code[LH.CodePos])^;
  1218.     Inc(LH.CodePos, SizeOf(LH.CodeBits));
  1219.     Inc(LH.CodeBytes, SizeOf(LH.CodeBits));
  1220.     LH.CodeBitsCount := LH_CodeBits;
  1221.     Result := LH.State;
  1222.   end;
  1223.  
  1224.   function LHReadCode(LH: PLHData; Bits: Integer): Integer;
  1225.   var
  1226.     I: Integer;
  1227.   begin
  1228.     Result := 0;
  1229.     for I := 0 to Bits -1 do
  1230.     begin
  1231.       if (LH.CodeBitsCount = 0) and (LHRead(LH) < LH_Ready) then Exit;
  1232.       Dec(LH.CodeBitsCount);
  1233.       Result := Result or (LH.CodeBits and 1) shl I;
  1234.       LH.CodeBits := LH.CodeBits shr 1;
  1235.     end;
  1236.   end;
  1237.  
  1238.   function LHUncompress(LH: PLHData): Integer;
  1239.   begin
  1240.     Result := LH_Root;
  1241.     repeat
  1242.       if (LH.CodeBitsCount = 0) and (LHRead(LH) < LH_Ready) then Exit;
  1243.       Dec(LH.CodeBitsCount);
  1244.       if LH.CodeBits and 1 <> 0 then Result := LH.Right[Result]
  1245.         else Result := LH.Left[Result];
  1246.       LH.CodeBits := LH.CodeBits shr 1;
  1247.     until Result >= LH.RangeMax;
  1248.     Dec(Result, LH.RangeMax);
  1249.     LHUpdateModel(LH, Result);
  1250.   end;
  1251.  
  1252.   function LHWrite(LH: PLHData): Boolean;
  1253.   begin
  1254.     LH.DataSize := LH.Write(LH.Data, LH.DataPos);
  1255.     if LH.DataSize = LH.DataPos then LH.CRC := LHUpdateCRC(LH, LH.Data, LH.DataSize)
  1256.       else LH.State := LH_ErrWrite;
  1257.     LH.DataPos := 0;
  1258.     Result := LH.State >= LH_Ready;
  1259.   end;
  1260.  
  1261. var
  1262.   C, L, I: Integer;
  1263. begin
  1264.   if LH.State = LH_Init then
  1265.   begin
  1266.     LHFill(@LH.TextPos, 10 * 4);
  1267.     LH.State := LH_Working;
  1268.  
  1269.     LH.RangeCopy  := 12;
  1270.     LH.RangeMax  := LH_FirstCode + (LH.RangeCopy * LH_CodesPerRange);
  1271.  
  1272.     LHInitCRC(LH);
  1273.     LHInitHuffman(LH);
  1274.     C := LHReadCode(LH, 1);
  1275.     if C <> 0 then
  1276. {$IFDEF LHCrypt}
  1277.       if LH.PC4_P <> 0 then
  1278.       begin
  1279.         C := LHReadCode(LH, 16);
  1280.         if C shr 8 xor C and $FF <> LH.PC4_P and $FF then
  1281.         begin
  1282.           LH.State := LH_ErrPassword;
  1283.           Exit;
  1284.         end;
  1285.       end else
  1286.       begin
  1287.         LH.State := LH_ErrProtected;
  1288.         Exit;
  1289.       end;
  1290. {$ELSE}
  1291.       begin
  1292.         LH.State := LH_ErrProtected;
  1293.         Exit;
  1294.       end;
  1295. {$ENDIF}
  1296.   end;
  1297.  
  1298.   if LH.State < LH_Working then Exit else
  1299.     if LH.State = LH_Working then C := LHUncompress(LH)
  1300.       else C := 0;
  1301.  
  1302.   while LH.State = LH_Working do
  1303.   begin
  1304.     if C < LH_Special then
  1305.     begin
  1306.       LH.Data[LH.DataPos] := C;
  1307.       Inc(LH.DataPos);
  1308.       if (LH.DataPos >= SizeOf(LH.Data)) and not LHWrite(LH) then Exit;
  1309.       Inc(LH.DataBytes);
  1310.       LH.Text[LH.TextPos] := C;
  1311.       Inc(LH.TextPos); if LH.TextPos >= LH_MaxSize then LH.TextPos := 0;
  1312.     end else
  1313.       if C >= LH_FirstCode then
  1314.       begin
  1315.         Dec(C, LH_FirstCode);
  1316.  
  1317.         I := C div LH_CodesPerRange;
  1318.         L := C mod LH_CodesPerRange + LH_MinCopy;
  1319.         C := LH.TextPos - (LHReadCode(LH, I +1) + L + LH.Range[I]);
  1320.  
  1321.         if C < 0 then Inc(C, LH_MaxSize);
  1322.         if (C < 0) or (C >= LH_MaxSize) then LH.State := LH_ErrInflate;
  1323.         if LH.State < LH_Ready then Exit;
  1324.  
  1325.         repeat
  1326.           LH.Data[LH.DataPos] := LH.Text[C];
  1327.           Inc(LH.DataPos);
  1328.           if (LH.DataPos >= SizeOf(LH.Data)) and not LHWrite(LH) then Exit;
  1329.           LH.Text[LH.TextPos] := LH.Text[C];
  1330.           Inc(LH.TextPos); if LH.TextPos >= LH_MaxSize then LH.TextPos := 0;
  1331.           Inc(C); if C >= LH_MaxSize then C := 0;
  1332.           Inc(LH.DataBytes);
  1333.           Dec(L);
  1334.         until L = 0;
  1335.       end else
  1336.       begin
  1337.         C := LHReadCode(LH, LH_SpecialBITS);
  1338.         case C of
  1339.           LH_SpecialINC:
  1340.             if LH.RangeCopy < LH_CopyRanges then
  1341.             begin
  1342.               Inc(LH.RangeCopy);
  1343.               LH.RangeMax := LH_FirstCode + (LH.RangeCopy * LH_CodesPerRange);
  1344.             end else
  1345.             begin
  1346.               LH.State := LH_ErrInflate;
  1347.               Exit;
  1348.             end;
  1349.           LH_SpecialEOF:
  1350.             begin
  1351.               LH.State := LH_Finish;
  1352.               Break;
  1353.             end;
  1354.           LH_SpecialCRC:
  1355.             if not LHReadCode(LH, 32) <> LHUpdateCRC(LH, LH.Data, LH.DataPos) then
  1356.             begin
  1357.               LH.State := LH_ErrCRC;
  1358.               Exit;
  1359.             end else
  1360.             begin
  1361.               LH.State := LH_Finish;
  1362.               Break;
  1363.             end;
  1364.         else
  1365.           begin
  1366.             LH.State := LH_ErrInflate;
  1367.             Exit;
  1368.           end;
  1369.         end;
  1370.       end;
  1371.     C := LHUncompress(LH);
  1372.   end;
  1373.  
  1374.   if LH.State = LH_Finish then
  1375.   begin
  1376.     if (LH.DataPos > 0) and not LHWrite(LH) then Exit;
  1377.     if LH.State > LH_Ready then LH.State := LH_Ready;
  1378.   end;
  1379. end;
  1380.  
  1381. function LHDecode(const Password: String; ReadProc: TReadProc; WriteProc: TWriteProc; Size: Integer): Integer;
  1382. var
  1383.   LH: PLHData;
  1384. begin
  1385.   try
  1386.     GetMem(LH, SizeOf(TLHInflate));
  1387.   except
  1388.     Result := LH_ErrAlloc;
  1389.     Exit;
  1390.   end;
  1391.   try
  1392.     LH.State := LH_Init;
  1393.     LH.Read := ReadProc;
  1394.     LH.Write := WriteProc;
  1395.     LH.InputSize := Size;
  1396. {$IFDEF LHCrypt}
  1397.     LHInitCrypt(LH, Password);
  1398. {$ENDIF}
  1399.     LHInflate(LH);
  1400.   finally
  1401.     Result := LH.State;
  1402.     if Result >= LH_Ready then Result := LH.DataBytes;
  1403.     LHFill(LH, SizeOf(TLHInflate));
  1404.     ReallocMem(LH, 0);
  1405.   end;
  1406. end;
  1407. {$ENDIF}
  1408.  
  1409. // internal used in Buffer En/Decoding
  1410. type
  1411.   PLHCallbackRec = ^TLHCallbackRec;
  1412.   TLHCallbackRec = packed record
  1413.     Buffer: PChar;
  1414.     BufferSize: Integer;
  1415.     Data: PChar;
  1416.     DataSize: Integer;
  1417.   end;
  1418.  
  1419.   TMethod = record
  1420.     Code, Data: Pointer;
  1421.   end;
  1422.  
  1423. function LHGetRead(R: PLHCallbackRec): TReadProc;
  1424.  
  1425.   function DoRead(R: PLHCallbackRec; var Buffer; Count: Integer): Integer; register;
  1426.   begin
  1427.     if Count > R.BufferSize then Count := R.BufferSize;
  1428.     Move(R.Buffer^, Buffer, Count);
  1429.     Inc(R.Buffer, Count);
  1430.     Dec(R.BufferSize, Count);
  1431.     Result := Count;
  1432.   end;
  1433.  
  1434. begin
  1435.   TMethod(Result).Data := R;
  1436.   TMethod(Result).Code := @DoRead;
  1437. end;
  1438.  
  1439. function LHGetWrite(R: PLHCallbackRec): TWriteProc;
  1440.  
  1441.   function DoWrite(R: PLHCallbackRec; const Buffer; Count: Integer): Integer; register;
  1442.   begin
  1443.     ReallocMem(R.Data, R.DataSize + Count);
  1444.     Move(Buffer, R.Data[R.DataSize], Count);
  1445.     Inc(R.DataSize, Count);
  1446.     Result := Count;
  1447.   end;
  1448.  
  1449. begin
  1450.   TMethod(Result).Data := R;
  1451.   TMethod(Result).Code := @DoWrite;
  1452. end;
  1453.  
  1454. {$IFDEF LHEncode}
  1455. function LHEncodeBuffer(const Password: String; const Buffer; BufferSize: Integer; out Data: Pointer): Integer;
  1456. var
  1457.   R: TLHCallbackRec;
  1458. begin
  1459.   Data := nil;
  1460.   R.Buffer := @Buffer;
  1461.   R.BufferSize := BufferSize;
  1462.   R.Data := nil;
  1463.   R.DataSize := 0;
  1464.   try
  1465.     Result := LHEncode(Password, LHGetRead(@R), LHGetWrite(@R), BufferSize, LH_Max);
  1466.     if Result >= LH_Ready then
  1467.     begin
  1468.       Data := R.Data;
  1469.       Result := R.DataSize;
  1470.     end;
  1471.   except
  1472.     Result := LH_ErrGeneric;
  1473.     ReallocMem(R.Data, 0);
  1474.   end;
  1475. end;
  1476. {$ENDIF}
  1477.  
  1478. {$IFDEF LHDecode}
  1479. function LHDecodeBuffer(const Password: String; const Buffer; BufferSize: Integer; out Data: Pointer): Integer;
  1480. var
  1481.   R: TLHCallbackRec;
  1482. begin
  1483.   Data := nil;
  1484.   R.Buffer := @Buffer;
  1485.   R.BufferSize := BufferSize;
  1486.   R.Data := nil;
  1487.   R.DataSize := 0;
  1488.   try
  1489.     Result := LHDecode(Password, LHGetRead(@R), LHGetWrite(@R), BufferSize);
  1490.     if Result >= LH_Ready then
  1491.     begin
  1492.       Data := R.Data;
  1493.       Result := R.DataSize;
  1494.     end;
  1495.   except
  1496.     Result := LH_ErrGeneric;
  1497.     ReallocMem(R.Data, 0);
  1498.   end;
  1499. end;
  1500. {$ENDIF}
  1501.  
  1502. function LHCheck(Code: Integer): Integer;
  1503. resourcestring
  1504.   sLHSZUnspecific = 'Error in LHSZ library';
  1505.   sLHSZAlloc      = 'Error in LHSZ memory allocation';
  1506.   sLHSZInit       = 'Error in LHSZ initialization';
  1507.   sLHSZRead       = 'Readerror in LHSZ library';
  1508.   sLHSZWrite      = 'Writeerror in LHSZ library';
  1509.   sLHSZInflate    = 'Infalteerror in LHSZ library';
  1510.   sLHSZWrongCRC   = 'Checksum Error in LHSZ library';
  1511.   sLHSZPassword   = 'Wrong Password in LHSZ library';
  1512.   sLHSZProtected  = 'LHSZ data are password protected';
  1513.  
  1514. const
  1515.   sError: array[-9..-1] of PResStringRec =
  1516.     (@sLHSZProtected, @sLHSZPassword, @sLHSZWrongCRC, @sLHSZInflate,
  1517.      @sLHSZWrite, @sLHSZRead, @sLHSZInit, @sLHSZAlloc, @sLHSZUnspecific);
  1518.  
  1519. begin
  1520.   if Code < LH_Ready then
  1521.   begin
  1522.     if Code < LH_ErrProtected then Code := LH_ErrGeneric;
  1523.     raise Exception.Create(LoadResString(sError[Code]));
  1524.   end else Result := Code;
  1525. end;
  1526.  
  1527. end.
  1528.  
  1529.