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;
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.
来源:https://stackoverflow.com/questions/30355553/delphi-lzma-decompression-sample