home *** CD-ROM | disk | FTP | other *** search
/ Windoware / WINDOWARE_1_6.iso / source / stream13 / huffman.pas < prev    next >
Pascal/Delphi Source File  |  1992-05-19  |  10KB  |  353 lines

  1. {$B-}   { Use fast boolean evaluation. }
  2.  
  3. unit Huffman;   { Copyright D.J. Murdoch, (1992) }
  4.  
  5. { Defines a Huffman compression filter to illustrate use of the TBitFilter. }
  6.  
  7. { The THuffmanFilter object defined in this file isn't optimized as much as
  8.   I'd like, so I haven't put it into the main Streams unit.  It's also a
  9.   little rough - be careful if you use it.  If you make any substantial
  10.   improvements, I'd like to see them! - djm}
  11.  
  12. interface
  13.  
  14. uses
  15.   {$ifdef windows}
  16.   wobjects,
  17.   {$else}
  18.   objects,
  19.   {$endif}
  20.   streams;
  21.  
  22. const
  23.   MaxNode = 510;
  24.   StoreSize = ((MaxNode-255)*18+7) div 8; { Bytes required to store the code
  25.                                             table }
  26.  
  27. type
  28.   PHuffmanfilter = ^THuffmanfilter;
  29.   THuffmanfilter = object(TBitfilter)
  30.     { This object defines a Huffman encoder/decoder which encodes the 256
  31.       letter alphabet of bytes using variable length codes in the 2 letter
  32.       alphabet of bits. }
  33.  
  34.     Size,                       { The size of the expanded stream. }
  35.     Position : LongInt;         { The current position in the expanded stream }
  36.  
  37.     Counts : array[0..MaxNode] of longint; { Counts uncompressed characters;
  38.                                          second half used as workspace }
  39.  
  40.     Decoder : array[256..MaxNode,TBit] of integer; { Array holding decoder }
  41.     EncodeStates : array[0..MaxNode] of integer;   { The state change array }
  42.     EncodeBits   : array[0..MaxNode] of TBit;      { The encoding bit for each
  43.                                                  state }
  44.     Learning : boolean;     { Signals whether writes are enabled, and whether
  45.                               to attempt to decode reads. }
  46.  
  47.     constructor init(ABase:PStream);
  48.     { Inits the Counts to 0, but doesn't set up a code.  Puts filter
  49.       in "learning" mode.  Before setting Learning to false, be sure to
  50.       call LoadCode or BuildCode. }
  51.  
  52.     procedure LoadCode;
  53.     { Reads an encoding from the base stream. }
  54.  
  55.     procedure StoreCode;
  56.     { Writes an encoding to the base stream. }
  57.  
  58.     procedure BuildCode;
  59.     { Builds the optimal encoding based on the values in the Counts array }
  60.  
  61.     procedure BuildEncoder(Verify:boolean);
  62.     { Initializes the Encode arrays based on the Decoder array.  Called
  63.       automatically by LoadCode and BuildCode; use this routine only
  64.       if you've loaded the Decoder in some other way. If Verify is true,
  65.       it will check that the Decoder array is valid. }
  66.  
  67.     function CodeBits(b:byte):word;
  68.     { Returns the number of bits that will be used in the current code
  69.       to write b. }
  70.  
  71.     function PredictedSize:Longint;
  72.     { Returns the predicted number of bytes to write the distribution of
  73.       bytes given in Counts in the current encoding. }
  74.  
  75.     procedure read(var buf; count:word); virtual;
  76.     procedure write(var buf; count:word); virtual;
  77.     function getpos:longint; virtual;
  78.     function getsize:longint; virtual;
  79.    end;
  80.  
  81. implementation
  82.  
  83. constructor THuffmanFilter.Init(ABase:PStream);
  84. begin
  85.   if not TFilter.Init(ABase) then
  86.     fail;
  87.   Size := 0;
  88.   Position := 0;
  89.   FillChar(counts,sizeof(counts),0);
  90.   Learning := true;
  91. end;
  92.  
  93. procedure THuffmanFilter.LoadCode;
  94. var
  95.   i,code : integer;
  96. begin
  97.   for i:=256 to MaxNode do
  98.   begin
  99.     ReadBits(code,9);
  100.     Decoder[i,0] := code;     { Should we confirm code<=MaxNode? }
  101.     ReadBits(code,9);
  102.     Decoder[i,1] := code;
  103.   end;
  104.   BuildEncoder(true);
  105. end;
  106.  
  107. procedure THuffmanFilter.StoreCode;
  108. var
  109.   i : integer;
  110. begin
  111.   for i:=256 to MaxNode do
  112.   begin
  113.     WriteBits(Decoder[i,0],9);
  114.     WriteBits(Decoder[i,1],9);
  115.   end;
  116. end;
  117.  
  118. procedure THuffmanFilter.BuildCode;
  119. var
  120.   letters : array[byte] of integer;  { The array of symbols }
  121.  
  122.     procedure Revsort;
  123.   { Procedure to do a Quicksort on the array of letters,
  124.     to put Counts[letters[i]] into decreasing order.
  125.     Ties are broken by the letter order.
  126.     Based on Quicksort as given in Steal This Code, by F.D. Boswell, Watcom 1986.
  127.   }
  128.     procedure quick(first,last : integer);
  129.     var
  130.       pivot : integer;
  131.       temp : integer;
  132.       scanright, scanleft : integer;
  133.     begin
  134.       if (first < last) then
  135.       begin
  136.         pivot := letters[first];
  137.         scanright := first;
  138.         scanleft := last;
  139.         while scanright < scanleft do
  140.         begin
  141.           if Counts[letters[scanright+1]] < Counts[pivot] then
  142.           begin
  143.             if Counts[letters[scanleft]] >= Counts[pivot] then
  144.             begin
  145.               temp := letters[scanleft];
  146.               inc(scanright);
  147.               letters[scanleft] := letters[scanright];
  148.               letters[scanright] := temp;
  149.               dec(scanleft);
  150.             end
  151.             else
  152.               dec(scanleft);
  153.           end
  154.           else
  155.             inc(scanright);
  156.         end;
  157.         temp := letters[scanright];
  158.         letters[scanright] := letters[first];
  159.         letters[first] := temp;
  160.         quick(first, scanright-1);
  161.         quick(scanright+1, last);
  162.       end;
  163.     end;
  164.   begin  {quicksort}
  165.     quick(0, 255);
  166.   end;
  167.  
  168. var
  169.   i,LastEntry,LastLetter,PrevLetter,InsertAt : integer;
  170. begin { BuildCode }
  171.   for i:=0 to 255 do
  172.     letters[i] := i;                 { Initialize to match counts }
  173.   RevSort;                        { Sort into decreasing frequency }
  174.   for i :=256 to MaxNode do
  175.   begin
  176.   { Create node by combining last two entries }
  177.     LastEntry := 511-i;
  178.     LastLetter := Letters[LastEntry];
  179.     PrevLetter := Letters[LastEntry-1];
  180.     Decoder[i,0] := PrevLetter;
  181.     Decoder[i,1] := LastLetter;
  182.     Counts[i] := Counts[PrevLetter] + Counts[LastLetter];
  183.   { Find where to insert it }
  184.     InsertAt := LastEntry-1;
  185.     While (InsertAt > 0) and (Counts[Letters[InsertAt-1]] <= Counts[i]) do
  186.       dec(InsertAt);
  187.   { Insert the node }
  188.     Move(Letters[InsertAt],Letters[InsertAt+1],
  189.          (LastEntry-1-InsertAt)*sizeof(Integer));
  190.     Letters[InsertAt] := i;
  191.   end;
  192.   BuildEncoder(false);
  193. end;
  194.  
  195. procedure THuffmanFilter.BuildEncoder(verify:boolean);
  196. var
  197.   i,code : integer;
  198.   j : TBit;
  199. begin
  200.   fillchar(EncodeBits,sizeof(EncodeBits),0);
  201.   if verify then
  202.   begin
  203.     { First, confirm that all the Decoder values are in range }
  204.     for i:=256 to MaxNode do
  205.       for j:=0 to 1 do
  206.         if (Decoder[i,j] < 0) or (Decoder[i,j] > MaxNode) then
  207.         begin
  208.           Error(stIntegrity,i);
  209.           exit;
  210.         end;
  211.     { Initialize the EncodeStates to illegal values to detect missing
  212.       codes }
  213.     fillchar(EncodeStates,sizeof(EncodeStates),0);
  214.   end;
  215.   for i:=256 to MaxNode do
  216.   begin
  217.     EncodeStates[Decoder[i,0]] := i;
  218.     code := Decoder[i,1];
  219.     EncodeStates[code] := i;
  220.     EncodeBits[code] := 1;
  221.   end;
  222.   if verify then
  223.     for i:=0 to pred(MaxNode) do
  224.       if EncodeStates[i] = 0 then
  225.       begin
  226.         Error(stIntegrity,i);
  227.         exit;
  228.       end;
  229. end;
  230.  
  231. function THuffmanFilter.CodeBits(b:byte):word;
  232. var
  233.   state : 0..MaxNode;
  234.   result : word;
  235. begin
  236.   result := 0;
  237.   state := b;
  238.   while state < MaxNode do
  239.   begin
  240.     inc(result);
  241.     state := EncodeStates[state];
  242.   end;
  243.   CodeBits := result;
  244. end;
  245.  
  246. function THuffmanFilter.PredictedSize:longint;
  247. var
  248.   bitcount : longint;
  249.   b : byte;
  250. begin
  251.   bitcount := 0;
  252.   for b:=0 to 255 do
  253.     inc(bitcount,Counts[b]*CodeBits(b));
  254.   PredictedSize := (bitcount+7) div 8;
  255. end;
  256.  
  257. procedure THuffmanFilter.Read(var buf;Count:word);
  258. var
  259.   i : word;
  260.   bbuf : TByteArray absolute buf;
  261.   State : 0..MaxNode;
  262. begin
  263.   if CheckStatus then
  264.   begin
  265.     if learning then
  266.       TBitFilter.Read(buf,Count)
  267.     else
  268.       for i:=0 to Count-1 do
  269.       begin
  270.         State := MaxNode;
  271.         repeat
  272.           State := Decoder[State,GetBit];
  273.         until State < 256;
  274.         bbuf[i] := State;
  275.       end;
  276.     for i:=0 to Count-1 do
  277.       inc(Counts[bbuf[i]]);
  278.     inc(position,Count);
  279.     if Position>Size then
  280.       Size := Position;
  281.     CheckBase;
  282.   end;
  283. end;
  284.  
  285. procedure THuffmanFilter.Write(var buf;Count:word);
  286. var
  287.   bbuf : TByteArray absolute buf;
  288.   i : word;
  289.   bitstack : word;
  290.   bitcount : word;
  291.   words : word;
  292.   state : 0..MaxNode;
  293. begin
  294.   if CheckStatus then
  295.   begin
  296.     for i:=0 to Count-1 do
  297.       inc(Counts[bbuf[i]]);
  298.     if not learning then
  299.     begin
  300.       for i:=0 to Count-1 do
  301.       begin
  302.         bitstack := 0;
  303.         bitcount := 0;
  304.         words := 0;
  305.         state := bbuf[i];
  306.         { Push all the bits onto the stack }
  307.         while state < MaxNode do
  308.         begin
  309.           bitstack := 2*bitstack + EncodeBits[state];
  310.           inc(bitcount);
  311.           if bitcount = 16 then
  312.           begin
  313.             asm
  314.               push bitstack
  315.             end;
  316.             bitstack := 0;
  317.             bitcount := 0;
  318.             inc(words);
  319.           end;
  320.           state := EncodeStates[state];
  321.         end;
  322.         { Now write out all the bits }
  323.         WriteBits(bitstack,bitcount);
  324.         while words > 0 do
  325.         begin
  326.           asm
  327.             pop bitstack
  328.           end;
  329.           WriteBits(BitStack,16);
  330.           dec(words);
  331.         end;
  332.       end;
  333.       inc(position,count);
  334.       if position>size then
  335.         size := position;
  336.       CheckBase;
  337.     end;
  338.   end;
  339. end;
  340.  
  341. function THuffmanFilter.GetPos:longint;
  342. begin
  343.   GetPos := Position;
  344. end;
  345.  
  346. function THuffmanFilter.GetSize:longint;
  347. begin
  348.   GetSize := Size;
  349. end;
  350.  
  351. end.
  352.  
  353.