*/
Know a good article or link that we're missing? Submit it!
*/

View \PIBLZW.INC

Lempel-Ziv-Welch compression method (pascal)

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


(*--------------------------------------------------------------------------*)
(*          Terminate --- Finish output file, close files.                  *)
(*--------------------------------------------------------------------------*)

PROCEDURE Terminate;

BEGIN (* Terminate *)
                                   (* Write any remaining characters *)
                                   (* to output file.                *)
   IF ( Output_Pos > 0 ) THEN
      BlockWrite( Output_File, Output_Buffer, Output_Pos );

   Ierr := IOResult;
                                   (* Close input and output files   *)
   CLOSE( Input_File  );
   Ierr := IOResult;

   CLOSE( Output_File );
   Ierr := IOResult;

END   (* Terminate *);

(*--------------------------------------------------------------------------*)
(*          Get_Hash_Code --- Gets hash code for given <w>C string          *)
(*--------------------------------------------------------------------------*)

FUNCTION Get_Hash_Code( PrevC, FollC : INTEGER ) : INTEGER;

VAR
   Index  : INTEGER;
   Index2 : INTEGER;

BEGIN (* Get_Hash_Code *)
                                   (* Get initial index using hashing *)

   Index := ( ( PrevC SHL 5 ) XOR FollC ) AND MaxTab;

                                   (* If entry not already used, return *)
                                   (* its index as hash code for <w>C.  *)

   IF ( NOT String_Table[Index].Used ) THEN
      Get_Hash_Code := Index
   ELSE
                                   (* If entry already used, search to  *)
                                   (* end of list of hash collision     *)
                                   (* entries for this hash code.       *)
                                   (* Do linear probe to find an        *)
                                   (* available slot.                   *)
      BEGIN

                                   (* Skip to end of collision list ... *)

         WHILE ( String_Table[Index].Next <> End_List ) DO
            Index := String_Table[Index].Next;

                                   (* Begin linear probe down a bit from  *)
                                   (* last entry in collision list ...    *)

         Index2 := ( Index + 101 ) AND MaxTab;

                                   (* Look for unused entry using linear  *)
                                   (* probing ...                         *)

         WHILE ( String_Table[Index2].Used ) DO
            Index2 := SUCC( Index2 ) AND MaxTab;

                                   (* Point prior end of collision list   *)
                                   (* to this new node.                   *)

         String_Table[Index].Next := Index2;

                                   (* Return hash code for <w>C           *)

         Get_Hash_Code          := Index2;

      END;

END   (* Get_Hash_Code *);

(*--------------------------------------------------------------------------*)
(*          Make_Table_Entry --- Enter <w>C string in string table          *)
(*--------------------------------------------------------------------------*)

PROCEDURE Make_Table_Entry( PrevC, FollC: INTEGER );

BEGIN (* Make_Table_Entry *)
                                   (* Only enter string if there is room left *)

   IF ( Table_Used <= MaxTab ) THEN
      BEGIN
         WITH String_Table[ Get_Hash_Code( PrevC , FollC ) ] DO
            BEGIN
               Used     := TRUE;
               Next     := End_List;
               PrevChar := PrevC;
               FollChar := FollC;
            END;
                                   (* Increment count of items used *)

         INC( Table_Used );
(*
         IF ( Table_Used > ( MaxTab + 1 ) ) THEN
            BEGIN
               WRITELN('Hash table full.');
            END;
*)
      END;

END   (* Make_Table_Entry *);

(*--------------------------------------------------------------------------*)
(*            Initialize_String_Table --- Initialize string table           *)
(*--------------------------------------------------------------------------*)

PROCEDURE Initialize_String_Table;

VAR
   I: INTEGER;

BEGIN (* Initialize_String_Table *)

                                   (* No entries used in table yet *)
   Table_Used  := 0;
                                   (* Clear all table entries      *)
   FOR I := 0 TO MaxTab DO
      WITH String_Table[I] DO
         BEGIN
            PrevChar := No_Prev;
            FollChar := No_Prev;
            Next     := -1;
            Used     := FALSE;
         END;
                                   (* Enter all single characters into *)
                                   (* table                            *)
   FOR I := 0 TO 255 DO
      Make_Table_Entry( No_Prev , I );

END   (* Initialize_String_Table *);

(*--------------------------------------------------------------------------*)
(*            Initialize --- Initialize compression/decompression           *)
(*--------------------------------------------------------------------------*)

PROCEDURE Initialize;

VAR
   Input_Name  : AnyStr            (* Input file name  *);
   Output_Name : AnyStr            (* Output file name *);

BEGIN (* Initialize *)
                                   (* Get the input file *)
   IF ( ParamCount > 0 ) THEN
      Input_Name := ParamStr( 1 )
   ELSE
      BEGIN

         CASE If_Compressing OF
            TRUE:  WRITE('Enter name of file to compress      : ');
            FALSE: WRITE('Enter name of file to decompress      : ');
         END (* CASE *);

         READLN( Input_Name );
         Ierr := IOResult;

      END;
                                   (* Open input file *)

   ASSIGN ( Input_File , Input_Name );
   RESET  ( Input_File , 1 );
   Ierr := IOResult;
                                   (* Get the output file *)
   IF ( ParamCount > 1 ) THEN
      Output_Name := ParamStr( 2 )
   ELSE
      BEGIN

         CASE If_Compressing OF
            TRUE:  WRITE('Enter name of output compressed file: ');
            FALSE: WRITE('Enter name of output uncompressed file: ');
         END (* CASE *);

         READLN( Output_Name );
         Ierr := IOResult;

      END;
                                   (* Open output file *)

   ASSIGN ( Output_File , Output_Name );
   REWRITE( Output_File , 1 );
   Ierr := IOResult;
                                   (* Point input point past end of *)
                                   (* buffer to force initial read  *)
   Input_Pos  := MaxBuff + 1;
                                   (* Nothing written out yet       *)
   Output_Pos := 0;
                                   (* Nothing read in yet           *)
   InBufSize  := 0;
                                   (* No input or output codes yet  *)
                                   (* constructed                   *)
   Output_Code := Empty;
   Input_Code  := Empty;
                                   (* Initialize string hash table  *)
   Initialize_String_Table;

END   (* Initialize *);

(*--------------------------------------------------------------------------*)
(*            Lookup_String --- Look for string <w>C in string table        *)
(*--------------------------------------------------------------------------*)

FUNCTION Lookup_String( PrevC, FollC: INTEGER ) : INTEGER;

VAR
   Index  : INTEGER;
   Index2 : INTEGER;
   Found  : BOOLEAN;

BEGIN (* Lookup_String *)
                                   (* Initialize index to check from hash *)

   Index       := ( ( PrevC SHL 5 ) XOR FollC ) AND MaxTab;

                                   (* Assume we won't find string *)
   Lookup_String := End_List;
                                   (* Search through list of hash collision *)
                                   (* entries for one that matches <w>C     *)
   REPEAT

      Found := ( String_Table[Index].PrevChar = PrevC ) AND
               ( String_Table[Index].FollChar = FollC );

      IF ( NOT Found ) THEN
         Index := String_Table[Index].Next;

   UNTIL Found OR ( Index = End_List );

                                   (* Return index if <w>C found in table. *)
   IF Found THEN
      Lookup_String := Index;

END   (* Lookup_String *);

(*--------------------------------------------------------------------------*)
(*              Get_Char  ---  Read character from input file               *)
(*--------------------------------------------------------------------------*)

PROCEDURE Get_Char( VAR C: INTEGER );

BEGIN (* Get_Char *)
                                   (* Point to next character in buffer *)
   INC( Input_Pos );
                                   (* If past end of block read in, then *)
                                   (* reset input pointer and read in    *)
                                   (* next block.                        *)

   IF ( Input_Pos > InBufSize ) THEN
      BEGIN
         BlockRead( Input_File, Input_Buffer, MaxBuff, InBufSize );
         Input_Pos := 1;
         Ierr      := IOResult;
      END;
                                  (* If end of file hit, return EOF_Char *)
                                  (* otherwise return next character in  *)
                                  (* input buffer.                       *)
   IF ( InBufSize = 0 ) THEN
      C := EOF_Char
   ELSE
      C := Input_Buffer[Input_Pos];

END   (* Get_Char *);

(*--------------------------------------------------------------------------*)
(*             Write_Char  ---  Write character to output file              *)
(*--------------------------------------------------------------------------*)

PROCEDURE Put_Char( C : INTEGER );

BEGIN (* Put_Char *)
                                   (* If buffer full, write it out and *)
                                   (* reset output buffer pointer.     *)

   IF ( Output_Pos >= MaxBuff ) THEN
      BEGIN
         BlockWrite( Output_File, Output_Buffer, MaxBuff );
         Output_Pos := 0;
         Ierr       := IOResult;
      END;
                                   (* Place character in next slot in  *)
                                   (* output buffer.                   *)

   INC( Output_Pos );
   Output_Buffer[Output_Pos] := C;

END   (* Put_Char *);

corner
© 1996-2008 CommunityHeaven LLC. 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.
North American business development: Nicolai Wadstrom. Publisher: Lars Hagelin.