xtool/precompressor/PrecompOodle.pas

826 lines
23 KiB
ObjectPascal

unit PrecompOodle;
interface
uses
OodleDLL, XDeltaDLL,
Utils,
PrecompUtils,
System.SysUtils, System.Classes, System.Types, System.Math;
{ 8C 07 - 0:LZH
8C 00 - 1:LZHLW
8C 01 - 2:LZNIB
CC 07 - 3:None
8C 02 - 4:LZB16
8C 03 - 5:LZBLW
8C 04 - 6:LZA
8C 05 - 7:LZNA
8C 06 - 8:Kraken
8C 0A - 9:Mermaid
8C 0B - 10:BitKnit
8C 0A - 11:Selkie
8C 0A - 12:Hydra
8C 0C - 13:Leviathan }
var
Codec: TPrecompressor;
implementation
const
OodleCodecs: array of PChar = ['lzna', 'kraken', 'mermaid', 'selkie', 'hydra',
'leviathan'];
CODEC_COUNT = 6;
LZNA_CODEC = 0;
KRAKEN_CODEC = 1;
MERMAID_CODEC = 2;
SELKIE_CODEC = 3;
HYDRA_CODEC = 4;
LEVIATHAN_CODEC = 5;
const
O_COUNT = 0;
O_TRADEOFF = 256;
O_MAXSIZE = 16 * 1024 * 1024;
var
SOList: array of array [0 .. CODEC_COUNT - 1] of TSOList;
OCount: Integer = O_COUNT;
OTradeOff: Integer = O_TRADEOFF;
CodecAvailable, CodecEnabled: TArray<Boolean>;
type
POodleSI = ^TOodleSI;
TOodleSI = record
CSize, DSize: Integer;
Codec: Integer;
HasCRC: Boolean;
end;
procedure GetOodleSI(Buff: PByte; Size: Integer; StreamInfo: POodleSI;
MaxBlocks: Integer = Integer.MaxValue; First: Boolean = True);
const
MinSize = 64;
BlkSize = 262144;
var
I, J, K: Integer;
Compressed: Boolean;
begin
if MaxBlocks <= 0 then
exit;
I := 0;
if First then
begin
StreamInfo^.CSize := 0;
StreamInfo^.DSize := 0;
StreamInfo^.Codec := 0;
StreamInfo^.HasCRC := False;
if Size < 8 then
exit;
if ((Buff^ in [$8C, $CC]) = False) then
exit;
Compressed := Buff^ = $8C;
if Compressed then
begin
case (Buff + 1)^ of
{ $02:
if not(((Buff + 2)^ shr 4 = 0) and (((Buff + 4)^ shr 4 = $F) or
((Buff + 4)^ and $F = $F))) then
exit; }
$06, $0A, $0C:
begin
I := EndianSwap(PInteger(Buff + 2)^) shr 8 + 6;
J := ((EndianSwap(PInteger(Buff + 5)^) shr 8) and $7FFFF) + 8;
if I > J then
begin
K := ((EndianSwap(PInteger(Buff + J)^) shr 8) and $7FFFF) + 3;
if I <> (J + K) then
exit;
end
else if I <> J then
exit;
end;
$86, $8A, $8C:
begin
StreamInfo^.HasCRC := True;
I := EndianSwap(PInteger(Buff + 2)^) shr 8 + 9;
J := ((EndianSwap(PInteger(Buff + 8)^) shr 8) and $7FFFF) + 11;
if I > J then
begin
K := ((EndianSwap(PInteger(Buff + J)^) shr 8) and $7FFFF) + 3;
if I <> (J + K) then
exit;
end
else if I <> J then
exit;
end;
else
exit;
end;
end
else
begin
if not(Buff + 1)^ in [ { $02, } $06, $0A, $0C] then
exit;
end;
case (Buff + 1)^ of
{ $02:
StreamInfo^.Codec := 0; // Old oodle }
$06, $86:
StreamInfo^.Codec := 1; // Kraken
$0A, $8A:
StreamInfo^.Codec := 2; // Mermaid/Selkie
$0C, $8C:
StreamInfo^.Codec := 3; // Leviathan
end;
end
else
begin
if not(Buff^ in [$0C, $4C]) then
exit;
Compressed := Buff^ = $0C;
if Compressed then
begin
case (Buff + 1)^ of
{ $02:
if not(((Buff + 2)^ shr 4 = 0) and (((Buff + 4)^ shr 4 = $F) or
((Buff + 4)^ and $F = $F))) then
exit; }
$06, $0A, $0C:
if not(Buff + 5)^ shr 4 in [3, 8] then
exit;
$86, $8A, $8C:
if not(Buff + 8)^ shr 4 in [3, 8] then
exit;
end;
end
else
begin
if not(Buff + 1)^ in [$06, $0A, $0C] then
exit;
end;
end;
if Compressed then
begin
case (Buff + 1)^ of
{ $02:
I := EndianSwap(PWord(Buff + 2)^) + 5; }
$06, $0A, $0C:
I := EndianSwap(PInteger(Buff + 2)^) shr 8 + 6;
$86, $8A, $8C:
I := EndianSwap(PInteger(Buff + 2)^) shr 8 + 9;
else
exit;
end;
if First and (I < MinSize) then
exit;
if StreamInfo^.CSize + I > Size then
begin
StreamInfo^.CSize := 0;
StreamInfo^.DSize := 0;
exit;
end;
if I = $00080005 then
I := 6;
Inc(StreamInfo^.CSize, I);
Inc(StreamInfo^.DSize, BlkSize);
Dec(MaxBlocks);
GetOodleSI(Buff + I, Size, StreamInfo, MaxBlocks, False);
end
else
begin
case (Buff + 1)^ of
$06, $0A, $0C:
begin
if (StreamInfo^.CSize + BlkSize + 3 <= Size) and
((Buff + BlkSize + 2)^ in [$0C, $4C]) and
((Buff + BlkSize + 3)^ = (Buff + 1)^) then
begin
Inc(StreamInfo^.CSize, BlkSize + 2);
Inc(StreamInfo^.DSize, BlkSize);
end
else if (First = False) and (StreamInfo^.CSize + 8 <= Size) then
begin
Inc(StreamInfo^.CSize, 8 + 2);
Inc(StreamInfo^.DSize, 8);
exit;
end
else
exit;
Dec(MaxBlocks);
GetOodleSI(Buff + BlkSize + 2, Size, StreamInfo, MaxBlocks, False);
end;
else
exit;
end;
end;
end;
procedure OodleDecompressCB(userdata: Pointer; rawBuf: PByte;
rawLen: NativeUInt; compBuf: PByte; compBufferSize, rawDone,
compUsed: NativeUInt);
begin
WriteLn(ErrOutput, rawDone);
end;
function LocalLZ_Decompress(asrc, adst: PByte; asrcSize, adstCapacity: Integer;
aIdent: Byte; out Res: Integer): Integer;
const
BlkSize = 262144;
var
A, B: Integer;
begin
B := IfThen(adstCapacity mod BlkSize = 0, Pred(adstCapacity div BlkSize),
adstCapacity div BlkSize) * BlkSize;
FillChar((adst + B)^, adstCapacity - B, aIdent);
Res := OodleLZ_Decompress(asrc, asrcSize, adst, adstCapacity);
A := Pred(adstCapacity);
while A > B do
begin
if (adst + A)^ <> aIdent then
break;
Dec(A);
end;
Inc(A);
Result := A;
end;
function CustomLZ_Decompress0(src, dst: PByte; srcSize, dstCapacity: Integer;
var Res: Integer): Boolean;
type
T3Res = array [0 .. 2] of Integer;
procedure AddRes(const I: Integer; var Res: T3Res);
begin
Res[0] := Res[1];
Res[1] := Res[2];
Res[2] := I;
end;
const
MinSize = 64;
BlkSize = 262144;
Range = 262144;
function ValidSize(Res: T3Res): Boolean;
const
ThresSize = 32;
begin
Result := (Res[0] > 0) and (Res[0] < Res[1]) and
InRange(Res[0], Res[0], Res[2] + 32);
end;
var
LBuffer: array [0 .. BlkSize - 1] of Byte;
I, J, W, X, Y, Z: Integer;
LR1, LR2: T3Res;
begin
Result := False;
Y := Max(LocalLZ_Decompress(src, dst, srcSize, dstCapacity, 0, Z),
LocalLZ_Decompress(src, dst, srcSize, dstCapacity, 1, Z));
if Y > MinSize then
begin
W := IfThen(Y mod BlkSize = 0, Pred(Y div BlkSize), Y div BlkSize)
* BlkSize;
Move((dst + W)^, LBuffer[0], Y - W);
end;
if (Y = Z) and (Y = dstCapacity) then
begin
Res := Y;
I := Max(LocalLZ_Decompress(src, dst, srcSize, dstCapacity - 1, 0, Z),
LocalLZ_Decompress(src, dst, srcSize, dstCapacity - 1, 1, Z));
if (Res <> I) and (Res <> Pred(I)) then
begin
Move(LBuffer[0], (dst + W)^, Res - W);
Result := True;
exit;
end;
end;
FillChar(LR1, SizeOf(T3Res), 0);
FillChar(LR2, SizeOf(T3Res), 0);
I := Y;
J := Min(dstCapacity, Y + Range);
while I < J do
begin
Y := Max(LocalLZ_Decompress(src, dst, srcSize, I, 0, Z),
LocalLZ_Decompress(src, dst, srcSize, I, 1, Z));
AddRes(Y, LR1);
AddRes(Z, LR2);
if (LR1[1] = LR2[1]) and ValidSize(LR1) then
begin
Res := LR1[1];
Move(LBuffer[0], (dst + W)^, Res - W);
Result := True;
break;
end;
if Y > MinSize then
begin
W := IfThen(Y mod BlkSize = 0, Pred(Y div BlkSize), Y div BlkSize)
* BlkSize;
Move((dst + W)^, LBuffer[0], Y - W);
end;
Inc(I);
end;
end;
function CustomLZ_DecompressN(src, dst: PByte; srcSize, dstCapacity: Integer;
var Res: TIntegerDynArray): Boolean;
const
BlkSize = 262144;
UpLen = 128;
DownLen = 16;
var
I, J, X, Y, Z: Integer;
Sizes: array [0 .. UpLen + DownLen - 1] of Integer;
begin
SetLength(Res, 0);
Y := Max(LocalLZ_Decompress(src, dst, srcSize, dstCapacity, 0, Z),
LocalLZ_Decompress(src, dst, srcSize, dstCapacity, 1, Z));
for I := Low(Sizes) to High(Sizes) do
Sizes[I] := -1;
J := Min(dstCapacity, Y + UpLen);
I := Max(IfThen(dstCapacity mod BlkSize = 0, Pred(dstCapacity div BlkSize),
dstCapacity div BlkSize) * BlkSize, Y - DownLen);
X := J - I;
while (J > I) do
begin
Y := Max(LocalLZ_Decompress(src, dst, srcSize, J, 0, Z),
LocalLZ_Decompress(src, dst, srcSize, J, 1, Z));
Sizes[Length(Sizes) - (J - I)] := Z;
Dec(J);
end;
for I := Low(Sizes) to High(Sizes) do
begin
X := Sizes[I];
for J := Low(Sizes) to High(Sizes) do
begin
Y := Sizes[J];
if I <> J then
if X = Y then
begin
Sizes[I] := -1;
Sizes[J] := -1;
end;
end;
end;
for I := Low(Sizes) to High(Sizes) do
if Sizes[I] > srcSize then
if OodleLZ_Decompress(src, srcSize, dst, Sizes[I]) = Sizes[I] then
begin
Insert(Sizes[I], Res, Length(Res));
if Length(Res) >= OCount then
break;
end;
Result := Length(Res) > 0;
end;
function GetOodleUS(Instance: Integer; Input: PByte; Pos: NativeInt;
StreamInfo: POodleSI; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs): Integer;
const
MinSize = 64;
var
Buffer: PByte;
B: Boolean;
I: Integer;
ResultN: TIntegerDynArray;
SI: _StrInfo1;
begin
Result := 0;
{ if StreamInfo^.Codec = 3 then
exit; }
// StreamInfo^.DSize:=$8001;
Buffer := Funcs^.Allocator(Instance, StreamInfo^.DSize);
if OCount <= 0 then
B := CustomLZ_Decompress0(Input + Pos, Buffer, StreamInfo^.CSize,
StreamInfo^.DSize, Result)
else
begin
B := CustomLZ_DecompressN(Input + Pos, Buffer, StreamInfo^.CSize,
StreamInfo^.DSize, ResultN);
if B then
Result := ResultN[0];
end;
If B then
if (Result > MinSize) and (Result > StreamInfo^.CSize) then
begin
Output(Instance, Buffer, Result);
SI.Position := Pos;
SI.OldSize := StreamInfo^.CSize;
SI.Option := 0;
SetBits(SI.Option, OTradeOff, 13, 11);
case StreamInfo^.Codec of
1:
SetBits(SI.Option, KRAKEN_CODEC, 0, 5);
2:
if CodecEnabled[MERMAID_CODEC] then
SetBits(SI.Option, MERMAID_CODEC, 0, 5)
else
SetBits(SI.Option, SELKIE_CODEC, 0, 5);
3:
SetBits(SI.Option, LEVIATHAN_CODEC, 0, 5);
end;
if CodecEnabled[HYDRA_CODEC] then
SetBits(SI.Option, HYDRA_CODEC, 0, 5);
SetBits(SI.Option, Integer(StreamInfo^.HasCRC), 12, 1);
SI.Status := TStreamStatus.None;
if OCount <= 0 then
begin
SI.NewSize := Result;
Funcs^.LogScan1(OodleCodecs[GetBits(SI.Option, 0, 5)], SI.Position,
SI.OldSize, SI.NewSize);
Add(Instance, @SI, nil, nil);
end
else
begin
if Length(ResultN) > 0 then
for I := Low(ResultN) to High(ResultN) do
begin
SI.NewSize := ResultN[I];
Funcs^.LogScan1(OodleCodecs[GetBits(SI.Option, 0, 5)], SI.Position,
SI.OldSize, SI.NewSize);
Add(Instance, @SI, nil, nil);
end;
end;
end;
end;
function GetOodleCodec(Index: Integer): Integer;
begin
case Index of
LZNA_CODEC:
Result := 7;
KRAKEN_CODEC:
Result := 8;
MERMAID_CODEC:
Result := 9;
SELKIE_CODEC:
Result := 11;
HYDRA_CODEC:
Result := 12;
LEVIATHAN_CODEC:
Result := 13;
else
Result := 8;
end;
end;
function OodleInit(Command: PChar; Count: Integer;
Funcs: PPrecompFuncs): Boolean;
var
I: Integer;
Options: TArray<Integer>;
S: String;
X, Y: Integer;
begin
Result := True;
SetLength(SOList, Count);
for X := Low(SOList) to High(SOList) do
for Y := Low(SOList[X]) to High(SOList[X]) do
SOList[X, Y] := TSOList.Create([], TSOMethod.MTF);
for X := Low(CodecAvailable) to High(CodecAvailable) do
begin
CodecAvailable[X] := False;
CodecEnabled[X] := False;
end;
for X := Low(CodecAvailable) to High(CodecAvailable) do
CodecAvailable[X] := OodleDLL.DLLLoaded;
X := 0;
while Funcs^.GetCodec(Command, X, False) <> '' do
begin
S := Funcs^.GetCodec(Command, X, False);
for Y := Low(OodleCodecs) to High(OodleCodecs) do
if (CompareText(S, OodleCodecs[Y]) = 0) and OodleDLL.DLLLoaded then
begin
CodecEnabled[Y] := True;
if Funcs^.GetParam(Command, X, 'l') <> '' then
for I := Low(SOList) to High(SOList) do
SOList[I][Y].Update
([StrToInt(Funcs^.GetParam(Command, X, 'l'))], True);
if Funcs^.GetParam(Command, X, 'n') <> '' then
OCount := StrToInt(Funcs^.GetParam(Command, X, 'n'));
if Funcs^.GetParam(Command, X, 't') <> '' then
OTradeOff := StrToInt(Funcs^.GetParam(Command, X, 't'));
end;
Inc(X);
end;
SetLength(Options, 0);
for I := 1 to 9 do
Insert(I, Options, Length(Options));
for X := Low(SOList) to High(SOList) do
for Y := Low(SOList[X]) to High(SOList[X]) do
if SOList[X, Y].Count = 0 then
SOList[X, Y].Update(Options);
end;
procedure OodleFree(Funcs: PPrecompFuncs);
var
X, Y: Integer;
begin
for X := Low(SOList) to High(SOList) do
for Y := Low(SOList[X]) to High(SOList[X]) do
SOList[X, Y].Free;
end;
function OodleParse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
var
S: String;
I, J: Integer;
begin
Result := False;
Option^ := 0;
SetBits(Option^, OTradeOff, 13, 11);
I := 0;
while Funcs^.GetCodec(Command, I, False) <> '' do
begin
S := Funcs^.GetCodec(Command, I, False);
for J := Low(OodleCodecs) to High(OodleCodecs) do
if (CompareText(S, OodleCodecs[J]) = 0) and OodleDLL.DLLLoaded then
begin
SetBits(Option^, J, 0, 5);
if Funcs^.GetParam(Command, I, 'l') <> '' then
SetBits(Option^, StrToInt(Funcs^.GetParam(Command, I, 'l')), 5, 7);
if String(Funcs^.GetParam(Command, I, 'c')) = '1' then
SetBits(Option^, 1, 12, 1);
if Funcs^.GetParam(Command, I, 't') <> '' then
SetBits(Option^, StrToInt(Funcs^.GetParam(Command, I, 't')), 13, 11);
Result := True;
end;
Inc(I);
end;
end;
procedure OodleScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
var
Buffer: PByte;
Pos: NativeInt;
X: Integer;
Res: Integer;
SI: _StrInfo1;
OodleSI: TOodleSI;
DI1, DI2: TDepthInfo;
DS: TPrecompStr;
begin
DI1 := Funcs^.GetDepthInfo(Instance);
DS := Funcs^.GetCodec(DI1.Codec, 0, False);
if DS <> '' then
begin
X := IndexTextW(@DS[0], OodleCodecs);
if (X < 0) or (DI1.OldSize <> SizeEx) then
exit;
if not CodecAvailable[X] then
exit;
if (X in [LZNA_CODEC, LEVIATHAN_CODEC]) and (DI1.NewSize <= 0) then
exit;
if DI1.NewSize <= 0 then
Res := O_MAXSIZE
else
Res := DI1.NewSize;
Buffer := Funcs^.Allocator(Instance, Res);
case X of
KRAKEN_CODEC, MERMAID_CODEC, SELKIE_CODEC, HYDRA_CODEC:
begin
if DI1.NewSize <= 0 then
begin
if not CustomLZ_Decompress0(Input, Buffer, DI1.OldSize, Res, Res)
then
Res := 0;
end
else
Res := OodleLZ_Decompress(Input, DI1.OldSize, Buffer, Res);
end;
else
begin
if DI1.NewSize > 0 then
Res := OodleLZ_Decompress(Input, DI1.OldSize, Buffer, Res)
else
Res := 0;
end;
end;
if (Res > DI1.OldSize) then
begin
Output(Instance, Buffer, Res);
SI.Position := 0;
SI.OldSize := DI1.OldSize;
SI.NewSize := Res;
SI.Option := 0;
SetBits(SI.Option, X, 0, 5);
if System.Pos(SPrecompSep2, DI1.Codec) > 0 then
SI.Status := TStreamStatus.Predicted
else
SI.Status := TStreamStatus.None;
DS := Funcs^.GetDepthCodec(DI1.Codec);
Move(DS[0], DI2.Codec, SizeOf(DI2.Codec));
DI2.OldSize := SI.NewSize;
DI2.NewSize := SI.NewSize;
Funcs^.LogScan1(OodleCodecs[GetBits(SI.Option, 0, 5)], SI.Position,
SI.OldSize, SI.NewSize);
Add(Instance, @SI, DI1.Codec, @DI2);
end;
exit;
end;
if BoolArray(CodecEnabled, False) then
exit;
Pos := 0;
while Pos < Size do
begin
GetOodleSI(Input + Pos, SizeEx - Pos, @OodleSI);
if (OodleSI.CSize > 0) then
begin
if GetOodleUS(Instance, Input, Pos, @OodleSI, Output, Add, Funcs) > 0 then
begin
Inc(Pos, OodleSI.CSize);
continue;
end;
end;
Inc(Pos);
end;
end;
function OodleScan2(Instance, Depth: Integer; Input: Pointer; Size: cardinal;
StreamInfo: PStrInfo2; Offset: PInteger; Output: _PrecompOutput;
Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
B: Boolean;
I: Integer;
ResultN: TIntegerDynArray;
X: Integer;
Res: Integer;
OodleSI: TOodleSI;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if (X <> LZNA_CODEC) and (StreamInfo^.OldSize <= 0) then
begin
GetOodleSI(Input, Size, @OodleSI);
StreamInfo^.OldSize := OodleSI.CSize;
end;
if StreamInfo^.NewSize > 0 then
begin
Buffer := Funcs^.Allocator(Instance, StreamInfo^.NewSize);
Res := OodleLZ_Decompress(Input, StreamInfo^.OldSize, Buffer,
StreamInfo^.NewSize);
if Res = StreamInfo^.NewSize then
begin
Output(Instance, Buffer, Res);
Result := True;
end;
end
else if (not X in [LZNA_CODEC, LEVIATHAN_CODEC]) and (StreamInfo^.NewSize <= 0)
then
begin
Buffer := Funcs^.Allocator(Instance, OodleSI.DSize);
if CustomLZ_Decompress0(Input, Buffer, StreamInfo^.OldSize,
OodleSI.DSize, Res) then
begin
Output(Instance, Buffer, Res);
StreamInfo^.NewSize := Res;
Funcs^.LogScan2(OodleCodecs[GetBits(StreamInfo^.Option, 0, 5)],
StreamInfo^.OldSize, StreamInfo^.NewSize);
Result := True;
end;
end;
end;
function OodleProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
Params: String;
I: Integer;
X, Y: Integer;
Res1: Integer;
Res2: NativeUInt;
COptions: TOodleLZ_CompressOptions;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
Y := GetOodleCodec(X);
Buffer := Funcs^.Allocator(Instance, OodleLZ_GetCompressedBufferSizeNeeded(Y,
StreamInfo^.NewSize));
SOList[Instance][X].Index := 0;
while SOList[Instance][X].Get(I) >= 0 do
begin
if StreamInfo^.Status = TStreamStatus.Predicted then
if GetBits(StreamInfo^.Option, 5, 7) <> I then
continue;
Move(OodleLZ_CompressOptions_GetDefault(Y, I)^, COptions,
SizeOf(TOodleLZ_CompressOptions));
COptions.sendQuantumCRCs := GetBits(StreamInfo^.Option, 12, 1) = 1;
COptions.spaceSpeedTradeoffBytes := GetBits(StreamInfo^.Option, 13, 11);
Params := 'l' + I.ToString + ':' + 'c' + GetBits(StreamInfo^.Option, 12, 1)
.ToString + ':' + 't' + GetBits(StreamInfo^.Option, 13, 11).ToString;
Res1 := OodleLZ_Compress(Y, NewInput, StreamInfo^.NewSize, Buffer, I,
@COptions);
Result := (Res1 = StreamInfo^.OldSize) and CompareMem(OldInput, Buffer,
StreamInfo^.OldSize);
Funcs^.LogProcess(OodleCodecs[GetBits(StreamInfo^.Option, 0, 5)],
PChar(Params), StreamInfo^.OldSize, StreamInfo^.NewSize, Res1, Result);
if Result or (StreamInfo^.Status = TStreamStatus.Predicted) then
break;
end;
if (Result = False) and ((StreamInfo^.Status = TStreamStatus.Predicted) or
(SOList[Instance][X].Count = 1)) and (DIFF_TOLERANCE > 0) then
begin
Buffer := Funcs^.Allocator(Instance, Res1 + Max(StreamInfo^.OldSize, Res1));
Res2 := PrecompEncodePatch(OldInput, StreamInfo^.OldSize, Buffer, Res1,
Buffer + Res1, Max(StreamInfo^.OldSize, Res1));
Funcs^.LogPatch1(StreamInfo^.OldSize, Res1, Res2,
Funcs^.AcceptPatch(StreamInfo^.OldSize, Res1, Res2));
if Funcs^.AcceptPatch(StreamInfo^.OldSize, Res1, Res2) then
begin
Output(Instance, Buffer + Res1, Res2);
SetBits(StreamInfo^.Option, 1, 31, 1);
SOList[Instance][X].Add(I);
Result := True;
end;
end;
if Result then
begin
SetBits(StreamInfo^.Option, I, 5, 7);
SOList[Instance][X].Add(I);
end;
end;
function OodleRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
Params: String;
X, Y: Integer;
Res1: Integer;
Res2: NativeUInt;
COptions: TOodleLZ_CompressOptions;
begin
Result := False;
X := GetBits(StreamInfo.Option, 0, 5);
if CodecAvailable[X] = False then
exit;
Y := GetOodleCodec(X);
Buffer := Funcs^.Allocator(Instance, OodleLZ_GetCompressedBufferSizeNeeded(Y,
StreamInfo.NewSize));
Move(OodleLZ_CompressOptions_GetDefault(Y, GetBits(StreamInfo.Option, 5, 7))^,
COptions, SizeOf(TOodleLZ_CompressOptions));
COptions.sendQuantumCRCs := GetBits(StreamInfo.Option, 12, 1) = 1;
COptions.spaceSpeedTradeoffBytes := GetBits(StreamInfo.Option, 13, 11);
Params := 'l' + GetBits(StreamInfo.Option, 5, 7).ToString + ':' + 'c' +
GetBits(StreamInfo.Option, 12, 1).ToString + ':' + 't' +
GetBits(StreamInfo.Option, 13, 11).ToString;
Res1 := OodleLZ_Compress(Y, Input, StreamInfo.NewSize, Buffer,
GetBits(StreamInfo.Option, 5, 7), @COptions);
Funcs^.LogRestore(OodleCodecs[GetBits(StreamInfo.Option, 0, 5)],
PChar(Params), StreamInfo.OldSize, StreamInfo.NewSize, Res1, True);
if GetBits(StreamInfo.Option, 31, 1) = 1 then
begin
Buffer := Funcs^.Allocator(Instance, Res1 + StreamInfo.OldSize);
Res2 := PrecompDecodePatch(InputExt, StreamInfo.ExtSize, Buffer, Res1,
Buffer + Res1, StreamInfo.OldSize);
Funcs^.LogPatch2(StreamInfo.OldSize, Res1, StreamInfo.ExtSize, Res2 > 0);
if Res2 > 0 then
begin
Output(Instance, Buffer + Res1, StreamInfo.OldSize);
Result := True;
end;
exit;
end;
if Res1 = StreamInfo.OldSize then
begin
Output(Instance, Buffer, StreamInfo.OldSize);
Result := True;
end;
end;
var
I: Integer;
initialization
Codec.Names := [];
for I := Low(OodleCodecs) to High(OodleCodecs) do
begin
Codec.Names := Codec.Names + [OodleCodecs[I]];
StockMethods.Add(OodleCodecs[I]);
end;
Codec.Initialised := False;
Codec.Init := @OodleInit;
Codec.Free := @OodleFree;
Codec.Parse := @OodleParse;
Codec.Scan1 := @OodleScan1;
Codec.Scan2 := @OodleScan2;
Codec.Process := @OodleProcess;
Codec.Restore := @OodleRestore;
SetLength(CodecAvailable, Length(Codec.Names));
SetLength(CodecEnabled, Length(Codec.Names));
end.