home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c019 / 5.ddi / LZW.ZIP / DOUGPACK.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-05-19  |  23.8 KB  |  659 lines

  1. unit DOUGPACK;
  2.  
  3.  
  4. {----------------------------------------------------------------------}
  5. {------  Turbo Pascal DOUGPACK unit written by Douglas Webb    --------}
  6. {----------------------------------------------------------------------}
  7. {------  DISCLAIMER:  There shall be no guarantee of the       --------}
  8. {------   suitability of this software for any purpose.  The   --------}
  9. {------   author shall not be liable for any damages arrising  --------}
  10. {------   from the use of this software.                       --------}
  11. {----------------------------------------------------------------------}
  12.  
  13.  
  14. { This unit was written to demonstrate how LZW compression can be used to
  15.   compress files. It's ability to do so depends highly on the type of data
  16.   being compressed.  Text files may compress to 30-50% their original size,
  17.   .EXE files to 60-80% of their original size, database files to 20-40% of
  18.   their original size, and unpatterned data may actually increase in size.
  19.  
  20.   This incarnation of the algorithm is optimized for speed, as much as is
  21.   possible in a high level language like pascal, and to a lesser
  22.   degree at this experimental stage, flexibility, not readability.
  23.  
  24.   CRC assembly language routines were furnished by:
  25.        Edwin T. Floyd [76067,747]
  26.  
  27.    This unit allows the user to compress data using a variation on the
  28.   standard LZW compression format, or conversely to decompress data that
  29.   was previously compressed by this unit.
  30.      This unit makes a few assumptions:
  31.           1) Data being compressed is being sent to a file.
  32.           2) Data being decompressed is coming from a file.
  33.    There are however a number of options as to where the compressed data
  34.   is coming from, and the decompressed data is going.
  35.  
  36.    In fact it requires that you pass the "Compress" procedure a procedural
  37.   parameter of type 'GetBytesProc' (declared below) which will accept 3
  38.   parameters and act in every way like a 'BlockRead' procedure call.
  39.   Compress will ask for data in chunks of 4K or so at a time. Your
  40.   procedure should return the data to be compressed:
  41.  
  42.   GetBytesProc = PROCEDURE(VAR DTA; NBytes:WORD; VAR Bytes_Got : WORD);
  43.  
  44.   DTA is the start of a memory location where the information returned
  45.   should be.  NBytes is the number of bytes requested.  The actual number
  46.   of bytes returned must be passed in Bytes_Got (if there is no more data
  47.   then 0 should be returned).
  48.  
  49.     "Decompress" requires a procedural parameter of type 'PutBytesProc'
  50.   which will accept 3 parameters, and must act in every way like a
  51.   'BlockWrite' procedure call.  It must accept the decompressed data
  52.   and do something with it.
  53.  
  54.   GetBytesProc = PROCEDURE(VAR DTA; NBytes:WORD; VAR Bytes_Got : WORD);
  55.  
  56.      Don't forget that as procedural parameters they must be compiled in the
  57.   'F+' state to avoid a catastrophe.
  58.  
  59.  
  60.   Unpleasant NOTE: My provisions for maintaining a CRC for the compressed
  61.     file seem to get into trouble if you try to compress/decompress multiple
  62.     runs of data successively.  You'll get a warning that the CRC is bad
  63.     when in fact results appear to indicate that this is not so. So you may
  64.     have to ignore the CRC unless you can figure out how it's broken.
  65.  
  66. }
  67.  
  68. interface
  69. uses crt,Dos,CRC;
  70.  
  71. {#T The_LZW_Algorithm }
  72. {     The compression algorithm :
  73.  
  74.           STRING = get input character
  75.           WHILE there are still input characters DO
  76.             CHARACTER = get input chracter
  77.             IF STRING+CHARACTER is in the string table THEN
  78.               STRING = STRING + character
  79.             ELSE
  80.               output the code for string
  81.               add STRING+CHARACTER to the string table
  82.               STRING = CHARACTER
  83.             END of IF
  84.           END of WHILE
  85.           output the code for string
  86.  
  87.       The decompression algorithm:
  88.  
  89.           Read OLD_CODE
  90.           output OLD_CODE
  91.           WHILE there are still input characters DO
  92.             Read New_CODE
  93.             IF NEW_CODE is not in the translation table THEN
  94.               STRING = get translation of OLD_CODE
  95.               STRING = STRING+CHARACTER
  96.             ELSE
  97.               STRING = get translation of NEW_CODE
  98.             END of IF
  99.             output STRING
  100.             CHARACTER = first character in STRING
  101.             add OLD_CODE+CHARACTER to the translation table
  102.             OLD_CODE = NEW_CODE
  103.           END WHILE
  104.  
  105.  
  106.     Wrinkles added to improve compression:
  107.      1: Sliding dictionary size, Always start with a 9 bit table, then
  108.        when it's full increase the table size to 10 bits, and so on until
  109.        the dictionary is as big as you intend to support (say 12-14 bits).
  110.      2: Empty the library after it fills up and start again.  This is useful
  111.        in files where the repetative elements in them may change positionally,
  112.        such as in picture files of one sort or another, and many .EXE files.
  113.        In some cases this may actually cost you some compression, but not often
  114.        and not very much in any event. Even smarter (but not implemented)
  115.        would be to monitor compression and clear/partial clear if compression
  116.        appears to be dropping.
  117.  
  118. }
  119.  
  120.  
  121.  
  122.  
  123. CONST                    
  124.   Bits = 12;           { This constant reflects the number of bits used to
  125.                          generate the dictionary to compress the data. Data
  126.                          must be decmpressed using the same dictionary size
  127.                          as was used when it was compressed. Setting the
  128.                          number of bits to 12, 13 or 14 affects several
  129.                          constants.
  130.                          Larger Files tend to compress better with a larger
  131.                          dictionaries.
  132.  
  133.                          Memory used by this unit is a function of Bits &
  134.                           and the associated constant Table_Size:
  135.                             14 : 110K; 13 : 65K;  12 : 45K
  136.                          All but about 5-10K of this is heap and is not
  137.                            needed (or in use) when the unit is not actually
  138.                          compressing or decompressing data.
  139.  
  140.                          If you change this value, change the value of
  141.                          Table_Size appropriately.
  142.                          }
  143.  
  144.  
  145.  
  146. TYPE
  147.   PutBytesProc = PROCEDURE(VAR DTA; NBytes:WORD; VAR Bytes_Put : WORD);
  148.   {#X GetBytesProc}
  149.   {  "Decompress" requires a procedural parameter of type 'PutBytesProc'
  150.   which will accept 3 parameters, and must act in every way like a
  151.   'BlockWrite' procedure call.  It must accept the decompressed data
  152.   and do something with it (like save it to a file).
  153.  
  154.    Don't forget that as procedural parameters they must be compiled in the
  155.   'F+' state to avoid a catastrophe. }
  156.  
  157.  
  158.   GetBytesProc = PROCEDURE(VAR DTA; NBytes:WORD; VAR Bytes_Got : WORD);
  159.  {#X PutBytesProc}
  160.  { The "Compress" procedure, requires that it be passed a procedural
  161.   parameter of type 'GetBytesProc' which will accept 3
  162.   parameters and act in every way like a 'BlockRead' procedure call.
  163.   Compress will ask for data in chunks of 4K or so at a time. Your
  164.   procedure should return the data to be compressed.
  165.  
  166.   DTA is the start of a memory location where the information returned
  167.   should be.  NBytes is the number of bytes requested.  The actual number
  168.   of bytes returned must be passed in Bytes_Got (if there is no more data
  169.   then 0 should be returned).
  170.  
  171.   Don't forget that as procedural parameters they must be compiled in the
  172.   'F+' state to avoid a catastrophe.
  173.   }
  174.  
  175.  
  176. Function Compress(VAR OutFile : File; VAR Bytes_Written:LongInt; GetBytes:GetBytesProc): Word;
  177. {#X Decompress The_LZW_Algorithm}
  178. { This function uses LZW compression to compress the contents of InFile,
  179.   and write them to OutFile, a CRC value for the original value is returned.
  180.   The size of the compressed output is returned in 'Bytes_Written'. }
  181.  
  182. Function Decompress(VAR InFile : File; UsedBits: Word; NoBytes : Longint; PutBytes: PutBytesProc): Word;
  183. {#X Compress The_LZW_Algorithm}
  184. { This is the decompression routine.  It takes a LZW format file, and
  185.     expands it to an output file.  The code here should be a fairly close
  186.     match to the algorithm above.
  187.  
  188.     Usedbits - How many bits was the dictionary used during compression
  189.                (this is to make sure decompression is the same.)
  190.     NoBytes  - How many bytes are being decompressed
  191. }
  192.  
  193.  
  194. implementation
  195.  
  196. {$R-}                    { Error checking slows things down by 200% }
  197.  
  198. CONST
  199.   Hashing_Shift = Bits - 8;
  200.   Max_Value = PRED((1 SHL Bits));     { Code indicating end of data. }
  201.   Max_Code = PRED(Max_Value);         { The maximum amount of table entries allowed. }
  202.   Buffer_Size = 4096;                 { Buffer for file I/O }
  203.   Terminator : Array[10..14] OF WORD = (1023,2047,4095,8191,16383);
  204.  
  205.  
  206. { IF Bits = 14 then define table size as 18041 }  { The string table size   }
  207. { IF Bits = 13 then define table size as 9029  }  {  must be a prime number }
  208. { IF Bits = 12 then define table size as 5021  }  {  about 25% larger than  }
  209.   Table_Size = 5021;                             {  2^Bits.                }
  210.  
  211.  
  212.  
  213.  
  214. TYPE
  215.  
  216.  
  217.   Buffer_Type = Array[1..Buffer_Size] of Byte;  { I/O buffers. }
  218.   Buffer_Ptr  = ^Buffer_Type;
  219.  
  220.   Stack_Array = Array[1..4000] of Byte;         { Decompression stack. }
  221.   Stack_Ptr   = ^Stack_Array;
  222.  
  223.   Word_Array  = Array[0..Table_Size] OF Integer;
  224.   Word_Ptr    = ^Word_Array;
  225.   Char_Array  = Array[0..Table_Size] OF BYTE;
  226.   Char_Ptr    = ^Char_Array;
  227.  
  228.  
  229.  
  230.  
  231. VAR
  232.   InBuf,OutBuf : Buffer_Ptr;
  233.   Code_Value,Prefix_Code : Word_Ptr;
  234.   Append_Character : Char_Ptr;
  235.  
  236.   Stack_Position : Word;
  237.   Stringy : Stack_Ptr;
  238.   NumRead : Word;
  239.   BitsC : Word;
  240.  
  241.  
  242.  
  243.  
  244. Function Input_Code(VAR InFile : File; BitsC : WORD; Resetf : BOOLEAN): WORD;
  245.  
  246. { This function feeds data to the decompression routine. }
  247.  
  248.  
  249. CONST
  250.   Input_Bit_Count : Integer = 0;
  251.   Input_Bit_Buffer : Longint = 0;
  252.   IBuffer_Count : Integer = SUCC(Buffer_Size);
  253.  
  254. VAR
  255.   Return_Value : Word;
  256.   Temp : LongInt;
  257.   Numread : WORD;
  258.  
  259. BEGIN
  260.   IF Resetf THEN                                { Reset everything to initial values. }
  261.     BEGIN
  262.       Input_Bit_Count := 0;
  263.       Input_Bit_Buffer  := 0;
  264.       IBuffer_Count := SUCC(Buffer_Size);
  265.     END;
  266.   While Input_Bit_Count < 25 DO                 {  Input_Bit_Count <= 24 }
  267.     BEGIN
  268.       IF IBuffer_Count < SUCC(Buffer_Size) THEN
  269.         BEGIN
  270.           Temp := InBuf^[IBuffer_Count];
  271.           INC(IBuffer_Count);
  272.         END
  273.       ELSE
  274.         BEGIN
  275.           BlockRead(InFile,InBuf^,Buffer_Size,NumRead);
  276.           Temp := InBuf^[1];
  277.           IBuffer_Count := 2;
  278.         END;
  279.  
  280.       Input_Bit_Buffer := Input_Bit_Buffer OR (Temp SHL (24-Input_Bit_Count));
  281.       INC(Input_Bit_Count,8);
  282.     END;
  283.   Return_Value := Input_Bit_Buffer SHR (32-BitsC);
  284.   Input_Bit_Buffer := Input_Bit_Buffer SHL BitsC;
  285.   DEC(Input_Bit_Count,BitsC);
  286.   Input_Code := Return_Value;
  287. END;                                     {  end of the compressed data.    }
  288.  
  289.  
  290.  
  291.  
  292.  
  293. Procedure Output_Code(VAR OutFile: File; _Code,BitsC : Word; VAR Bytes_Written: Longint);
  294.  
  295.   { This procedure dumps the output of the compression routine to disk. }
  296.  
  297. CONST
  298.   Output_Bit_Count : Integer = 0;
  299.   Output_Bit_Buffer : Longint = 0;
  300.   OBuffer_Count : Integer = 1;
  301.  
  302. VAR
  303.   Code : LongInt;
  304.   temp : LongInt;
  305.   A    : Byte;
  306.  
  307.  
  308. BEGIN
  309.   Code := _Code;                { Convert form Word to LONGINT. }
  310.   Output_Bit_Buffer := Output_Bit_Buffer OR (Code SHL (32-BitsC-Output_Bit_Count));
  311.   INC(Output_Bit_Count,BitsC);
  312.   WHILE Output_Bit_Count >= 8 DO
  313.     BEGIN
  314.       OutBuf^[OBuffer_Count] := OutPut_Bit_Buffer SHR 24;
  315.       IF (OBuffer_Count <> Buffer_Size) AND (Code <> Max_Value) THEN
  316.         INC(OBuffer_Count)
  317.       ELSE
  318.         BEGIN
  319.           IF _Code <> Max_Value THEN
  320.             BEGIN
  321.               BlockWrite(OutFile,OutBuf^,Buffer_Size,NumRead);
  322.               OBuffer_Count := 1;
  323.               INC(Bytes_Written,NumRead);
  324.             END
  325.           ELSE
  326.             BEGIN              (* Flushing out the last few bytes *)
  327.               WHILE Output_Bit_Count > Bits - BitsC DO
  328.                 BEGIN
  329.                   DEC(Output_Bit_Count,8);
  330.                   INC(OBuffer_Count);
  331.                   Output_Bit_Buffer := Output_Bit_Buffer SHL 8;
  332.                   OutBuf^[OBuffer_Count] := OutPut_Bit_Buffer SHR 24;
  333.                 END;
  334.               BlockWrite(OutFile,OutBuf^,PRED(OBuffer_Count),NumRead);
  335.               INC(Bytes_Written,NumRead);
  336.               Output_Bit_Buffer := 0;        { Reset for next time. }
  337.               Output_Bit_Count := 8;         { Reset for next time. }
  338.             END;
  339.           OBuffer_Count := 1;
  340.         END;
  341.       Output_Bit_Buffer := Output_Bit_Buffer SHL 8;
  342.       DEC(Output_Bit_Count,8);
  343.     END;
  344. END;
  345.  
  346.  
  347.  
  348.  
  349.  
  350. Function Compress(VAR OutFile : File; VAR Bytes_Written:LongInt; GetBytes:GetBytesProc): Word;
  351.  
  352. { This function uses LZW compression to compress the contents of InFile,
  353.   and write them to OutFile, a CRC value for the original value is returned. }
  354.  
  355. LABEL
  356.   1;
  357.  
  358.  
  359. VAR
  360.   NumRead,String_Code,Next_Code : WORD;
  361.   I,J : INTEGER;
  362.   Character,Temp: Byte;
  363.   IBuffer_Count : WORD;
  364.   X : Longint;
  365.   Index,Offset : Integer;
  366.   CRCVal : WORD;
  367.   NotPacked : BOOLEAN;
  368.  
  369.  
  370. BEGIN
  371.   New(InBuf);                   { Create all the structures that will }
  372.   New(OutBuf);                  {  be needed to compress the data.    }
  373.   New(Code_Value);
  374.   New(Prefix_Code);
  375.   New(Append_Character);
  376.  
  377.  
  378.   NotPacked := TRUE;
  379.   Bytes_Written :=  0;
  380.   BitsC := 9;                    { Starting size of library. }
  381.   CRCVal := 0;                   { Initialize the CRC value. }
  382.   Next_Code := 256;
  383.   FOR I := 0 TO Table_Size DO    { Clear the string table before starting. }
  384.     Code_Value^[I] := -1;
  385.   GetBytes(Temp,1,Numread);      { Get the first Code.   }
  386.   GetBytes(InBuf^,1,Numread);
  387.   IBuffer_Count := Numread;  { Set Byte buffer empty. }
  388.   CRCVal := UpdateCRCArc(CRCVal,Temp,1);               { Update CRC value. }
  389.   CRCVal := UpdateCRCArc(CRCVal,InBuf^,NumRead);       { Update CRC value. }
  390.   String_Code := Temp;
  391.  
  392.   { This is the main loop where it all happens.  This loop runs until all
  393.      of the input file has been read.  Note that it clears the table
  394.      and restarts once all possible codes have been defined.       }
  395.  
  396.   While NotPacked DO
  397.     BEGIN
  398.       IF IBuffer_Count <> Numread THEN
  399.         BEGIN
  400.           Character := InBuf^[IBuffer_Count];
  401.           INC(IBuffer_Count);
  402.         END
  403.       ELSE
  404.         BEGIN
  405.            Character := InBuf^[IBuffer_Count];
  406.            GetBytes(InBuf^,Buffer_Size,Numread);
  407.            CRCVal := UpdateCRCArc(CRCVal,InBuf^,NumRead);   { Update CRC value. }
  408.            IBuffer_Count := 1;
  409.            If Numread = 0 THEN NotPacked := FALSE;          { If there is no more data then stop.}
  410.         END;
  411.  
  412. { This is the hashing code routine.  It tries to find a match for prefix+char
  413.    string in the string table.  If it finds it, the index is returned.  IF
  414.    the string is not found, the first available index in the string table is
  415.    returned instead.
  416. }
  417.       Index := (Character SHL Hashing_Shift) XOR String_Code;
  418.       IF Index = 0 THEN Offset := 1
  419.       ELSE Offset := Table_Size - Index;
  420.       WHILE TRUE DO
  421.         BEGIN
  422.           IF Code_Value^[Index] = -1 THEN
  423.             Goto 1;
  424.           IF (Prefix_Code^[Index] = String_Code) AND
  425.                         (Append_Character^[Index] = Character) THEN
  426.             Goto 1;
  427.           DEC(Index,Offset);
  428.           IF Index < 0 THEN INC(Index,Table_Size);
  429.         END;
  430.  
  431.                                                   { See if it's already in }
  432. 1:    IF Code_Value^[Index] <> -1 THEN            { the table. If it is,   }
  433.         String_Code := Code_Value^[Index]         { get the code value. If }
  434.       ELSE                                        { the string is not in   }
  435.         BEGIN                                     { table try to add it.   }
  436.           IF Next_Code < Max_Code THEN    { Actually this IF is redundant, will NEVER be false. }
  437.             BEGIN
  438.               Code_Value^[Index] := Next_Code;
  439.               INC(Next_Code);
  440.               Prefix_Code^[Index] := String_Code;
  441.               Append_Character^[Index] := Character;
  442.               Output_Code(OutFile,String_Code,BitsC,Bytes_Written);     { When a string is found    }
  443.               IF (Next_Code DIV (1 SHL BitsC)) = 1 THEN
  444.                 INC(BitsC);                         { Sliding window.     }
  445.               String_Code := Character;             { that is not in the table  }
  446.               IF Next_Code = Max_Code THEN       { Table is full. }
  447.                 BEGIN
  448.                   BitsC := 9;                    { Reset the sliding dictionary. }
  449.                   Next_Code := 256;
  450.                   FOR J := 0 TO Table_Size DO    { Clear the string table before }
  451.                     Code_Value^[J] := -1;        {  starting to fill it again.   }
  452.                 END;
  453.             END;
  454.  
  455.         END;                                    { I output the last string  }
  456.     END;                                        { after adding the new one. }
  457.  
  458.   { End of the main loop }
  459.  
  460.   Output_Code(OutFile,String_Code,BitsC,Bytes_Written); { Output the last code.                }
  461.   BitsC := Bits;
  462.   Output_Code(OutFile,Max_Value,BitsC,Bytes_Written);   { Output the end of buffer code.       }
  463.  
  464.   Dispose(OutBuf);                  { Deallocate all our structures. }
  465.   Dispose(InBuf);
  466.   Dispose(Code_Value);
  467.   Dispose(Prefix_Code);
  468.   Dispose(Append_Character);
  469.  
  470.   Compress := CRCVal;
  471. END;
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480. Function Decompress(VAR InFile : File; UsedBits: Word; NoBytes : LongInt; PutBytes: PutBytesProc): Word;
  481.  
  482. { This is the decompression routine.  It takes a LZW format file, and
  483.     expands it to an output file.  The code here should be a fairly close
  484.     match to the algorithm above.
  485. }
  486.  
  487.  
  488.  
  489. VAR
  490.   Next_Code,Code,New_Code,Old_Code : WORD;
  491.   I,Character : Integer;
  492.   Temp : Byte;
  493.   OBuffer_Count : WORD;
  494.   CRCVal : WORD;
  495.   CarryBits : Word;
  496.   BytesDeCompressed : LongInt;
  497.  
  498.  
  499.  
  500.  
  501. BEGIN
  502.   If UsedBits <> Bits THEN       { If compressed with different # bits }
  503.     BEGIN                        {   abort now.                        }
  504.       Decompress := 0;
  505.       Exit;
  506.     END;
  507.  
  508.  
  509.   New(InBuf);                     { Create all the structure which }
  510.   New(OutBuf);                    {  will allow me to decompress   }
  511.   New(Stringy);                   {  the data.                     }
  512.   New(Code_Value);
  513.   New(Prefix_Code);
  514.   New(Append_Character);
  515.  
  516.   BytesDeCompressed := 0;
  517.   CarryBits := 0;
  518.   BitsC := 9;                     { Initialize a few variables.    }
  519.   CRCVal := 0;
  520.   OBuffer_Count := 1;
  521.   Stack_Position := 1;
  522.   Next_Code := 256;           { This is the next available code to define. }
  523.   Old_Code := Input_Code(InFIle,BitsC,TRUE); { Read in the first code, initialize the }
  524.   BytesDeCompressed := BytesDeCompressed + (CarryBits + BitsC) DIV 8;
  525.   CarryBits := (CarryBits + BitsC) MOD 8;
  526.   Character := Old_Code;                { character variable, and send the first }
  527.   Temp := Old_Code;
  528.   PutBytes(Temp,1,NumRead);             { code to the output file.   }
  529.   CRCVal := UpdateCRCArc(CRCVal,Temp,1);       { Update CRC value. }
  530.  
  531.  
  532.  { This is the main decompression loop.  It read characters from the LZW file
  533.    until it sees the special code used to indicate the end of the data.
  534.  }
  535.  
  536.   New_Code := Input_Code(InFile,BitsC,FALSE);
  537.   BytesDeCompressed := BytesDeCompressed + (CarryBits + BitsC) DIV 8;
  538.   CarryBits := (CarryBits + BitsC) MOD 8;
  539.   While (New_Code <> Terminator[BitsC]) OR (BytesDeCompressed < NoBytes -2) DO
  540.     BEGIN
  541.  
  542.       { This code checks for special STRING+CHARACTER+STRING+CHARACTER+STRING
  543.          case which generates an undefined code.  It handles it by decoding
  544.          the last code, adding a single character to the end of the decode string.
  545.       }
  546.       IF New_Code = Next_Code THEN
  547.         BEGIN
  548.           Stringy^[Stack_Position] := Character;
  549.           INC(Stack_Position);
  550.  
  551.       { This routine simply decodes a string from the string table, storing
  552.          it in a buffer.  The buffer can then be output in reverse order by the
  553.          expansion routine (below).
  554.       }
  555.           Code := Old_Code;
  556.           While Code > 255 DO
  557.             BEGIN
  558.               Stringy^[Stack_Position] := Append_Character^[Code];
  559.               INC(Stack_Position);
  560.               Code := Prefix_Code^[Code];
  561.               IF Stack_Position >= 4000 THEN
  562.                 BEGIN
  563.                   Writeln('Fatal Error during code decompression.');
  564.                   Halt;
  565.                 END;
  566.             END;
  567.           Stringy^[Stack_Position] := Code;
  568.         END
  569.       { Otherwise do a straight decode of the new code. }
  570.       ELSE
  571.         BEGIN
  572.           Code := New_Code;
  573.           While Code > 255 DO
  574.             BEGIN
  575.               Stringy^[Stack_Position] := Append_Character^[Code];
  576.               INC(Stack_Position);
  577.               Code := Prefix_Code^[Code];
  578.               IF Stack_Position >= 4000 THEN
  579.                 BEGIN
  580.                   Writeln('Fatal Error during code decompression.');
  581.                   Halt;
  582.                 END;
  583.             END;
  584.           Stringy^[Stack_Position] := Code;
  585.         END;
  586.  
  587.       { Now output the decoded string in reverse order. }
  588.       Character := Stringy^[Stack_Position];
  589.       While (Stack_Position >= 1) DO
  590.         BEGIN
  591.           IF (OBuffer_Count <> Buffer_Size) THEN
  592.             BEGIN
  593.               OutBuf^[OBuffer_Count] := Stringy^[Stack_Position];
  594.               INC(OBuffer_Count);
  595.             END
  596.           ELSE
  597.             BEGIN
  598.               OutBuf^[Buffer_Size] := Stringy^[Stack_Position];
  599.               PutBytes(OutBuf^,Buffer_Size,NumRead);
  600.               CRCVal := UpdateCRCArc(CRCVal,OutBuf^,NumRead);       { Update CRC value. }
  601.               OBuffer_Count := 1;
  602.             END;
  603.  
  604.           DEC(Stack_Position);
  605.         END;
  606.       INC(Stack_Position);
  607.  
  608.       { Finally, if possible add a new code to the string table. }
  609.       IF Next_Code < Max_Code-1 THEN
  610.         BEGIN
  611.           Prefix_Code^[Next_Code] := Old_Code;
  612.           Append_Character^[Next_Code] := Character;
  613.           INC(Next_Code);
  614.           IF (SUCC(Next_Code)  DIV (1 SHL BitsC)) = 1 THEN
  615.             IF BitsC < Bits THEN INC(BitsC);
  616.         END;
  617.       IF Next_Code = Max_Code-1 THEN          { Table is now full. }
  618.         BEGIN
  619.           BitsC := 9;                         { Reset sliding dictionary. }
  620.           Stack_Position := 1;
  621.           Next_Code := 256;                   { This is the next available code to define. }
  622.           New_Code := Input_Code(InFile,BitsC,FALSE);
  623.           BytesDeCompressed := BytesDeCompressed + (CarryBits + BitsC) DIV 8;
  624.           CarryBits := (CarryBits + BitsC) MOD 8;
  625.           Character := New_Code;              { Reinitialize the decode process. }
  626.           IF (OBuffer_Count <> Buffer_Size) THEN
  627.             BEGIN
  628.               OutBuf^[OBuffer_Count] := New_Code;
  629.               INC(OBuffer_Count);
  630.             END
  631.           ELSE
  632.             BEGIN
  633.               OutBuf^[Buffer_Size] := New_Code;
  634.               CRCVal := UpdateCRCArc(CRCVal,OutBuf^,Buffer_Size);       { Update CRC value. }
  635.               PutBytes(OutBuf^,Buffer_Size,NumRead);
  636.               OBuffer_Count := 1;
  637.             END;
  638.         END;
  639.       Old_Code := New_Code;
  640.       New_Code := Input_Code(Infile,BitsC,FALSE);
  641.       BytesDeCompressed := BytesDeCompressed + (CarryBits + BitsC) DIV 8;
  642.       CarryBits := (CarryBits + BitsC) MOD 8;
  643.    END;
  644.   CRCVal := UpdateCRCArc(CRCVal,OutBuf^,PRED(OBuffer_Count));       { Update CRC value. }
  645.   PutBytes(OutBuf^,PRED(OBuffer_Count),NumRead);
  646.  
  647.   Dispose(OutBuf);                   { Deallocate all our structures. }
  648.   Dispose(InBuf);
  649.   Dispose(Stringy);
  650.   Dispose(Code_Value);
  651.   Dispose(Prefix_Code);
  652.   Dispose(Append_Character);
  653.   Decompress := CRCVal;
  654. END;
  655.  
  656.  
  657.  
  658.  
  659. END.