Written some cool source code? Upload it to Programmer's Heaven.

View \PIBDCOMP.PAS

Lempel-Ziv-Welch compression method (pascal)

Submitted By: Unknown
Rating: (Not rated) (Rate It)


(*$R-,V-,S-,I-*)
PROGRAM PibDComp;

(*--------------------------------------------------------------------------*)
(*                                                                          *)
(*       Program:  PibDComp                                                 *)
(*                                                                          *)
(*       Purpose:  Decompresses a file compressed using Lempel-Ziv-Welch    *)
(*                 appraoch by PibCompr.                                    *)
(*                                                                          *)
(*       Use:      PIBDCOMP  inputfile outputfile                           *)
(*                                                                          *)
(*                    inputfile  --- the input file to be decompressed      *)
(*                    outputfile --- the output decompressed file           *)
(*                                                                          *)
(*       Remarks:                                                           *)
(*                                                                          *)
(*          PibDComp uncompresses a file compressed by PibCompr.            *)
(*                                                                          *)
(*       Algorithm:                                                         *)
(*                                                                          *)
(*          The decompression algorithm translates each received            *)
(*          code into a prefix string and extension [suffix] character.     *)
(*          The extension character is stored (in a push-down stack),       *)
(*          and the prefix translated again, until the prefix is a          *)
(*          single character, which completes decompression of this         *)
(*          code.  The entire code is then output by popping the stack.     *)
(*                                                                          *)
(*          "An update to the string table is made for each code received   *)
(*          (except the first one).  When a code has been translated,       *)
(*          its final character is used as the extension character,         *)
(*          combined with the prior string, to add a new string to          *)
(*          the string table.  This new string is assigned a unique         *)
(*          code value, which is the same code that the compressor          *)
(*          assigned to that string.  In this way, the decompressor         *)
(*          incrementally reconstructs the same string table that           *)
(*          the decompressor used.... Unfortunately ... [the algorithm]     *)
(*          does not work for an abnormal case.                             *)
(*                                                                          *)
(*          The abnormal case occurs whenever an input character string     *)
(*          contains the sequence C<w>C<w>C, where C<w> already             *)
(*          appears in the compressor string table."                        *)
(*                                                                          *)
(*          The decompression algorithm, augmented to handle                *)
(*          the abnormal case, is as follows:                               *)
(*                                                                          *)
(*            1. Read first input code;                                     *)
(*               Store in CODE and OLDcode;                                 *)
(*               With CODE = code(C), output(C);  FINchar = C;              *)
(*            2. Read next code to CODE; INcode = CODE;                     *)
(*               If at end of file, exit;                                   *)
(*            3. If CODE not in string table (special case) then            *)
(*                  Output(FINchar);                                        *)
(*                  CODE = OLDcode;                                         *)
(*                  INcode = code(OLDcode, FINchar);                        *)
(*            4. If CODE == code(<w>C) then                                 *)
(*                  Push C onto the stack;                                  *)
(*                  CODE == code(<w>);                                      *)
(*                  Goto 4.                                                 *)
(*            5. If CODE == code(C) then                                    *)
(*                  Output C;                                               *)
(*                  FINchar = C;                                            *)
(*            6. While stack not empty                                      *)
(*                  Output top of stack;                                    *)
(*                  Pop stack;                                              *)
(*            7. Put OLDcode,C into the string table.                       *)
(*               OLDcode = INcode;                                          *)
(*               Goto 2.                                                    *)
(*                                                                          *)
(*       Reference:                                                         *)
(*                                                                          *)
(*          "A Technique for High Performance Data Compression",            *)
(*          Terry A. Welch, IEEE Computer,                                  *)
(*          vol. 17, no. 6 (June 1984), pp. 8-19.                           *)
(*                                                                          *)
(*       Note:  The hashing algorithm used here isn't very good, and        *)
(*              should be replaced by a better one.                         *)
(*                                                                          *)
(*       Usage note:                                                        *)
(*                                                                          *)
(*          You may use this program in any way you see fit without         *)
(*          restriction.  I'd appreciate a citation if you do use this      *)
(*          code in a program you distribute.                               *)
(*                                                                          *)
(*--------------------------------------------------------------------------*)

(*$I PIBLZW.DEF *)

CONST
   MaxStack = 4096                 (* Decompression stack size  *);

VAR
                                   (* Decompression stack       *)

   Stack         : ARRAY[1..MaxStack] OF INTEGER;

   Stack_Pointer : INTEGER         (* Decompression stack depth *);

(*$I PIBLZW.INC *)

(*--------------------------------------------------------------------------*)
(*                  Push --- Push character onto stack                      *)
(*--------------------------------------------------------------------------*)

PROCEDURE Push( C : INTEGER );

BEGIN (* Push *)

  INC( Stack_Pointer );
  Stack[ Stack_Pointer ] := C;

  IF ( Stack_Pointer >= MaxStack ) THEN
     BEGIN
        WRITELN('Stack overflow!');
        Terminate;
        Halt;
     END;

END  (* Push *);

(*--------------------------------------------------------------------------*)
(*                  Pop --- Pop character from stack                        *)
(*--------------------------------------------------------------------------*)

PROCEDURE Pop( VAR C : INTEGER );

BEGIN (* Pop *)

   IF ( Stack_Pointer > 0 ) THEN
      BEGIN
         C := Stack[Stack_Pointer];
         DEC( Stack_Pointer );
      END
   ELSE
      C := Empty;

END   (* Pop *);

(*--------------------------------------------------------------------------*)
(*            Get_Code --- Get compression code from input file             *)
(*--------------------------------------------------------------------------*)

PROCEDURE Get_Code( VAR Hash_Code : INTEGER );

VAR
   Local_Buf : INTEGER;

BEGIN (* Get_Code *)

   IF ( Input_Code = Empty ) THEN
      BEGIN

         Get_Char( Local_Buf );

         IF ( Local_Buf = EOF_Char ) THEN
            BEGIN
               Hash_Code := EOF_Char;
               EXIT;
            END;

         Get_Char( Input_Code );

         IF ( Input_Code = EOF_Char ) THEN
            BEGIN
               Hash_Code := EOF_Char;
               EXIT;
            END;

         Hash_Code  := ( ( Local_Buf SHL 4  ) AND $FF0 ) +
                       ( ( Input_Code SHR 4 ) AND $00F );

         Input_Code := Input_Code AND $0F;

      END
   ELSE
      BEGIN

         Get_Char( Local_Buf );

         IF ( Local_Buf = EOF_Char ) THEN
            BEGIN
               Hash_Code := EOF_Char;
               EXIT;
            END;

         Hash_Code  := Local_Buf + ( ( Input_Code SHL 8 ) AND $F00 );
         Input_Code := Empty;

      END;

END   (* Get_Code *);

(*--------------------------------------------------------------------------*)
(*            Do_Decompression --- Perform decompression                    *)
(*--------------------------------------------------------------------------*)

PROCEDURE Do_Decompression;

VAR
   C         : INTEGER             (* Current input character *);
   Code      : INTEGER             (* Current code string     *);
   Old_Code  : INTEGER             (* Previous code string    *);
   Fin_Char  : INTEGER             (* Final input character   *);
   In_Code   : INTEGER             (* Current input code      *);
   Last_Char : INTEGER             (* Previous character      *);
   Unknown   : BOOLEAN             (* TRUE if code not found  *);
   Temp_C    : INTEGER             (* Char popped off stack   *);

BEGIN (* Do_Decompression *)
                                   (* Decompression stack is empty *)
  Stack_Pointer := 0;
                                   (* First string is always known *)
  Unknown       := FALSE;
                                   (* Get first string == Step 1   *)
  Get_Code( Old_Code );

  Code          := Old_Code;
                                   (* Output corresponding character *)

  C    := String_Table[Code].FollChar;

  Put_Char( C );
                                   (* Remember this character  -- it    *)
                                   (* is final character of next string *)
  Fin_Char := C;
                                   (* Get next code  == Step 2 *)
  Get_Code( In_Code );

  WHILE( In_Code <> EOF_Char ) DO
     BEGIN
                                   (* Set code to this input code *)
        Code := In_Code;
                                   (* If code not in table, do special *)
                                   (* case ==> Step 3                  *)

        IF ( NOT String_Table[Code].Used ) THEN
           BEGIN
              Last_Char := Fin_Char;
              Code      := Old_Code;
              Unknown   := TRUE;
           END;
                                   (* Run through code extracting single *)
                                   (* characters from code string until  *)
                                   (* no more characters can be removed. *)
                                   (* Push these onto stack.  They will  *)
                                   (* be entered in reverse order, and   *)
                                   (* will come out in forwards order    *)
                                   (* when popped off.                   *)
                                   (*                                    *)
                                   (* ==> Step 4                         *)

        WHILE( String_Table[Code].PrevChar <> No_Prev ) DO
           WITH String_Table[Code] DO
              BEGIN
                 Push( FollChar );
                 Code := PrevChar;
              END;
                                   (* We now have the first character in *)
                                   (* the string.                        *)

        Fin_Char := String_Table[Code].FollChar;

                                   (* Output first character  ==> Step 5   *)
        Put_Char( Fin_Char );
                                   (* While the stack is not empty, remove *)
                                   (* and output all characters from stack *)
                                   (* which are rest of characters in the  *)
                                   (* string.                              *)
                                   (*                                      *)
                                   (* ==> Step 6                           *)
        Pop( Temp_C );

        WHILE( Temp_C <> Empty ) DO
           BEGIN
              Put_Char( Temp_C );
              Pop( Temp_C );
           END;
                                   (* If code isn't known, output the      *)
                                   (* follower character of last character *)
                                   (* of string.                           *)
        IF Unknown THEN
           BEGIN
              Fin_Char := Last_Char;
              Put_Char( Fin_Char );
              Unknown  := FALSE;
           END;
                                   (* Enter code into table ==> Step 7 *)

        Make_Table_Entry( Old_Code , Fin_Char );

                                   (* Make current code the previous code *)
        Old_Code := In_Code;

                                   (* Get next code  == Step 2 *)
        Get_Code( In_Code );

     END;

END   (* Do_Decompression *);

(*--------------------------------------------------------------------------*)
(*                     PibDComp --- Main program                            *)
(*--------------------------------------------------------------------------*)

BEGIN (* PibDComp *)
                                   (* Indicate we are doing decompression *)
   If_Compressing := FALSE;
                                   (* Initialize for deceompression       *)
   Initialize;
                                   (* Perform decompression               *)
   Do_Decompression;
                                   (* Clean up and exit                   *)
   Terminate;

END   (* PibDComp *).

corner
© 1996-2008. All rights reserved. Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
Publisher: Lars Hagelin.
bootstrapLabs Logo A bootstrapLabs project.