Listing 18


//das Beispiel zeigt die Kompression nach dem LZSS Algorhithmus, der eine Erweiterung des
//LZ77 ist
//im Unterschied zum LZ77 wird hier geprüft, ob die Länge des Kompr.'zeigers nicht größer der
//Länge der Zeichen ist, auf die der Kompr.'zeiger zeigt
//es wird ein ID-Bit eingeführt, welches bei der Dekompression angibt ob ein Zeiger oder ein
//einzelnes Zeichen folgt

unit LZSS;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TCompress = record //Struktur des Kompressionszeigers
     Pos: Word;
     Len: Byte;
     Car: Char;
  end;
  
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Edit1: TEdit;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

const
  Bits: array[0..7] of Byte = (1, 2, 4, 8, 16, 32, 64, 128);

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure SetBits(var b: string; bitco: Word; isset: Boolean);
var byt, bit: Byte;

begin
if Length(b)<(bitco div 8)+1 then b:=b+chr(0);

byt:=ord(b[(bitco div 8)+1]);
bit:=bitco-(bitco div 8)*8; 

if isset then
begin
   if (byt and Bits[bit])=0 then byt:=byt+Bits[bit];
end
else
begin
   if (byt and Bits[bit])<>0 then byt:=byt-Bits[bit];
end;

b[(bitco div 8)+1]:=chr(byt);
end;

function GetBits(b: string; bitco: Word): Boolean;
var byt, bit: Byte;

begin
byt:=ord(b[(bitco div 8)+1]);
bit:=bitco-(bitco div 8)*8;

result:=((byt and Bits[bit])<>0);
end;

procedure LZSSCompress(ofn, sfn: string);
var fo, fs: file;
    fsize: Integer;
    cv, vv, po, posps, bitco, bl: Word;
    s, p, b: string;
    buf: array[1..High(Word)] of Char;
    Temp: TCompress;

begin   

AssignFile(fo, ofn);
{$I-}
Reset(fo, 1);
{$I+}

AssignFile(fs, sfn);
{$I-}
Rewrite(fs, 1);
{$I+}

if IOResult = 0 then
begin
//Achtung: das Beispiel kann nur Dateigrößen <= High(Word) bearbeiten !!!
fsize:=FileSize(fo);
BlockRead(fo, buf, fsize);

s:=buf;

cv:=1; vv:=0; po:=0; b:=''; bitco:=0;
while cv<=fsize do
begin
   p:=Copy(s, vv+1, cv-vv);
   posps:=Pos(p, s);
   if (cv<fsize) and (Length(p)<256) and (posps>0) and (posps<=(vv+1)-Length(p)) then
      po:=posps
   else
   begin
      Temp.Pos:=po;
      Temp.Len:=Length(p)-1;
      Temp.Car:=s[cv];
      if Temp.Len>3 then
      begin
         SetBits(b, bitco, True);
         BlockWrite(fs, Temp, sizeof(TCompress));
      end
      else
      begin
         SetBits(b, bitco, False);
         BlockWrite(fs, p[1], sizeof(Char));
         cv:=vv+1;
      end;
      inc(bitco);
      
      vv:=cv; po:=0; 
   end;

   inc(cv);
end;

BlockWrite(fs, b[1], Length(b)); 
BlockWrite(fs, bitco, sizeof(Word)); 
end;

CloseFile(fo);
CloseFile(fs); 
end;

procedure LZSSDeCompress(ofn, sfn: string);
var fo, fs: file;
    fsize: Integer;
    cv, vv, bitco, bl: Word;
    s, p, b: string;
    buf: array[1..High(Word)] of Char;
    Temp: TCompress;

begin

AssignFile(fo, ofn);
{$I-}
Reset(fo, 1);
{$I+}

AssignFile(fs, sfn);
{$I-}
Rewrite(fs, 1);
{$I+}

if IOResult = 0 then
begin
fsize:=FileSize(fo);

Seek(fo, fsize-sizeof(Word));
BlockRead(fo, bitco, sizeof(Word)); bl:=bitco div 8; if bitco<>(bitco div 8)*8 then inc(bl);
Seek(fo, fsize-sizeof(Word)-bl);
BlockRead(fo, buf, bl);

b:=buf; 

Seek(fo, 0);

s:='';

for cv:=0 to bitco-1 do
begin
   if GetBits(b, cv) then
   begin
      BlockRead(fo, Temp, sizeof(TCompress));
      p:='';
      p:=Copy(s, Temp.Pos, Temp.Len);
      p:=p+Temp.Car;
   end
   else
   begin
      p:=chr(0);
      BlockRead(fo, p[1], sizeof(Char));
   end;

   s:=s+p;
end;

BlockWrite(fs, s[1], Length(s));
end;

CloseFile(fo);
CloseFile(fs); 
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
caption:='Kompression ...';
LZSSCompress(Edit1.Text, ChangeFileExt(Edit1.Text, '.cmp'));
caption:='OK';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
caption:='Dekompression ...';
LZSSDeCompress(ChangeFileExt(Edit1.Text, '.cmp'), ChangeFileExt(Edit1.Text, 'Kopie'+ExtractFileExt(Edit1.Text)));
caption:='OK';
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
if OpenDialog1.execute then
   Edit1.Text:=OpenDialog1.FileName;
end;

end.



Zurück zur Hauptseite