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