Delphi LZMA Decompression sample

2020-05-06 08:39发布

问题:

I found in this thread link of the delphi-zip library that has implementation of LZMA. But I can't make proper use of Decompression from it. Can some one write a little decompression sample for me, using this library?

Here is my code, it works for compression but didn't work for decompression and return 0 size

uses System.Zip.LZMA;

....

procedure TForm2.CompressProgress(Sender: TObject; const aPosition, aSize, aCompressedSize: UInt64);
begin
end;

procedure TForm2.DecompressProgress(Sender: TObject; const aPosition, aSize: UInt64);
begin
end;

procedure TForm2.CompressButton1Click(Sender: TObject);
var LZI: TLZMAEncoderStream;  OutStream, InStream: TMemoryStream;
begin
     OutStream:= TMemoryStream.Create;
     LZI := TLZMAEncoderStream.Create(OutStream,  CompressProgress);
     InStream:= TMemoryStream.Create;
     InStream.LoadFromFile('1.exe');
     InStream.Position := 0;
     LZI.Write(InStream, InStream.Size);
     OutStream.Position := 0;
     OutStream.SaveToFile('1.exe.lzma');
     InStream.Free;
     OutStream.Free;
     LZI.Free;
end;

procedure TForm2.DecompressButton2Click(Sender: TObject);
var Deca: TLZMADecoderStream;    Str1: TMemoryStream; S2 : TBytesStream;  J, I: Cardinal;
begin
    I := 0;
    Str1 := TMemoryStream.Create;
    Str1.LoadFromFile('1.exe.lzma');
    Str1.Position := 0;
    Deca:= TLZMADecoderStream.Create(Str1, DecompressProgress);

   S2   := TBytesStream.Create;
   J := Deca.Read(S2.Bytes, 0, i);

    Caption := IntToStr(J);

   S2.Position := 0;
   S2.SaveToFile('1.exe');

   Deca.Free;
   Str1.Free;
   S2.Free;
end;

also I tried do like this, but still not work

procedure TForm2.Button2Click(Sender: TObject);
var Deca: TLZMADecoderStream;    Str1 : TMemoryStream;  S2:TBytesStream;  J, I: Cardinal;
begin
    I := 0;
    Str1 := TMemoryStream.Create;
    Str1.LoadFromFile('1.exe.lzma');
    Str1.Position := 0;
    Deca:= TLZMADecoderStream.Create(Str1, DeProgress);

   S2   := TBytesStream.Create;
   Deca.Position := 0;
   J := Deca.Read(S2.Bytes, 0, Deca.Size);
   Caption := IntToStr(J);
   S2.Position := 0;
   S2.SaveToFile('Dec0.exe');
   Deca.Free;
   Str1.Free;
   S2.Free;
end;

回答1:

You asked to read zero bytes and that's what you got. You will need to loop reading chunks of data out of the stream. Keep looping until Read returns zero. Remember that Read returns the number of bytes read.

I'd use functions like this:

procedure LZMAcompress(InStream, OutStream: TStream);
var
  Encoder: TLZMAEncoderStream;
begin
  Encoder := TLZMAEncoderStream.Create(OutStream, nil);
  try
    Encoder.Write(InStream, InStream.Size);
  finally
    Encoder.Free;
  end;
end;

procedure LZMAdecompress(InStream, OutStream: TStream; Count: Int64);
const
  BufferSize = 1024*1024;
var
  Decoder: TLZMADecoderStream;
  Buffer: TBytes;
  BytesRead, BytesToRead: Integer;
begin
  Decoder := TLZMADecoderStream.Create(InStream, nil);
  try
    SetLength(Buffer, BufferSize);
    repeat
      BytesToRead := Min(Count, BufferSize);
      BytesRead := Decoder.Read(Buffer, BytesToRead);
      OutStream.Write(Buffer, BytesRead);
      dec(Count, BytesRead);
    until Count=0;
  finally
    Decoder.Free;
  end;
end;

And there's absolutely no need for memory streams here. Two file streams are what is needed.

The big issue that you will face is that the library you have chosen to use requires you to know how large the file is that you are decompressing. If you try to read more bytes than are available, then this library code enters a non-terminating loop. Hence my Count parameter in LZMAdecompress.

My suspicion is that the library that you have chosen to use, or at least the classes that you have chosen to use, are ill suited to your needs. I've only had a quick look through the code but it doesn't look good to me. Any compression library that has a non-terminating loop when presented with invalid data is not very useful. I would shun this library on this evidence. If I were you I would call the LZMA C API directly.

Perhaps your other problem is that you have made erroneous changes to the library that you are using. Don't do that. Go back to the original version from github.



标签: delphi lzma