Delphi Xe4. There is a set of components for data compression : ABBREVIA (http://tpabbrevia.sourceforge.net) It implements LZMA compression, and a module AbLZMA.pas (Lzma compression / decompression routines).
Use it :
...
Uses ablzma;
...
procedure TForm1.Button1Click(Sender: TObject);
var f1,f2:tfilestream;
begin
f1:=tfilestream.Create('d:\1.test',fmOpenRead);
f2:=tfilestream.Create('d:\1.lzma',fmCreate);
LzmaEncodeStream(f1,f2,f1.Size);
f2.Free;
f1.Free;
end;
...
Everything is working fine.
Questions:
In module AbLZMA.pas (also tried to use AbLZMAStream.pas) is the main procedure LzmaEnc_Encode, who works at a call LzmaEncodeStream:
function LzmaEnc_Encode(p: CLzmaEncHandle; outStream: PISeqOutStream;
inStream: PISeqInStream; Progress: PICompressProgress;
Alloc, allocBig: PISzAlloc): SRes; cdecl; external;
It has a parameter "Progress: PICompressProgress;", where
ICompressProgress = packed record
Progress: function(p: Pointer; inSize, outSize: Int64): SRes; cdecl;
end;
PICompressProgress = ^ICompressProgress;
I tried to add a procedure in the module AbLZMA.pas:
function MyProgress(p: Pointer; inSize, outSize: Int64): SRes;cdecl;
begin
// what is "p"?
// form1.caption:=result //?
end;
...
procedure LzmaEncodeStream(ASourceStream, ATargetStream: TStream; ASourceSize: Int64);
var
...
PMyProgress:PICompressProgress;
begin
...
PMyProgress.Progress:=MyProgress;
...
LzmaCheck(LzmaEnc_Encode(LEncHandle, @LOutStreamRec.Intf, @LInStreamRec.Intf,
{nil}PMyProgress // this
,@DelphiMMInterface, @DelphiMMInterface));
...
end;
In this case (even if the body of the procedure blank), getting Error AV. How to get the data from the current percentage of completion?
You have to allocate an ICompressProgress
variable. You've declared a pointer to one, but then never pointed it at anything.
Do it like this:
procedure LzmaEncodeStream(ASourceStream, ATargetStream: TStream;
ASourceSize: Int64);
var
MyProgress: ICompressProgress;
begin
...
MyProgress.Progress:=MyProgress;
...
LzmaCheck(LzmaEnc_Encode(LEncHandle, @LOutStreamRec.Intf, @LInStreamRec.Intf,
@MyProgress, @DelphiMMInterface, @DelphiMMInterface));
...
end;
You are calling LzmaEnc_Encode
which is the raw LZMA C interface. The progress callback documentation should exist in the LZMA SDK, but I cannot as yet find any good documentation. I suspect that you'll need to read the C implementation of LZMA to get to the bottom of this.
OK, here's the code that calls your progress callback:
for (;;)
{
res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
if (res != SZ_OK || p->finished != 0)
break;
if (progress != 0)
{
res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
if (res != SZ_OK)
{
res = SZ_ERROR_PROGRESS;
break;
}
}
}
The progress callback passes the PICompressProgress
in the first parameter. This allows you to declare your ICompressProgress
record with extra fields and so allow your callback function to receive state information. The inSize
parameter is the position in the input stream. You can make a progress value by dividing inSize
by the size of the input stream. And the outSize
parameter is, presumably, the number of bytes written so far in the output file.
If you return any value of than SZ_OK
then the operation will be cancelled.