source upload

This commit is contained in:
Razor12911
2022-01-17 22:16:47 +02:00
parent 12936d065b
commit 098e8c48de
1778 changed files with 1206749 additions and 0 deletions

View File

@@ -0,0 +1,163 @@
unit PrecompCrypto;
interface
uses
Utils,
PrecompUtils,
System.SysUtils, System.Classes, System.Math;
var
Codec: TPrecompressor;
implementation
const
CryptoCodecs: array of PChar = ['xor', 'aes', 'rc4'];
CODEC_COUNT = 3;
XOR_CODEC = 0;
AES_CODEC = 1;
RC4_CODEC = 2;
function CryptoInit(Command: PChar; Count: Integer;
Funcs: PPrecompFuncs): Boolean;
begin
Result := True;
end;
procedure CryptoFree(Funcs: PPrecompFuncs);
begin
end;
function CryptoParse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
var
S: String;
I: Integer;
begin
Result := False;
Option^ := 0;
I := 0;
while Funcs^.GetCodec(Command, I, False) <> '' do
begin
S := Funcs^.GetCodec(Command, I, False);
if (CompareText(S, CryptoCodecs[XOR_CODEC]) = 0) then
begin
SetBits(Option^, 0, 0, 5);
Result := True;
end
else if (CompareText(S, CryptoCodecs[AES_CODEC]) = 0) then
begin
SetBits(Option^, 1, 0, 5);
Result := True;
end
else if (CompareText(S, CryptoCodecs[RC4_CODEC]) = 0) then
begin
SetBits(Option^, 2, 0, 5);
Result := True;
end;
Inc(I);
end;
end;
procedure CryptoScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
begin
end;
function CryptoScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Res: Integer;
begin
Result := False;
Res := 0;
Funcs^.GetResource(StreamInfo^.Resource, nil, @Res);
if (Res > 0) or (StreamInfo^.OldSize > 0) or
(StreamInfo^.OldSize = StreamInfo^.NewSize) then
begin
Output(Instance, Input, StreamInfo^.OldSize);
Result := True;
end;
end;
function CryptoProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X: Integer;
Res: Integer;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
Res := 0;
Funcs^.GetResource(StreamInfo^.Resource, nil, @Res);
Buffer := Funcs^.Allocator(Instance, Res);
if Funcs^.GetResource(StreamInfo^.Resource, Buffer, @Res) then
begin
case X of
XOR_CODEC:
Funcs^.Decrypt('xor', NewInput, StreamInfo^.NewSize, Buffer, Res);
AES_CODEC:
Funcs^.Decrypt('aes', NewInput, StreamInfo^.NewSize, Buffer, Res);
RC4_CODEC:
Funcs^.Decrypt('rc4', NewInput, StreamInfo^.NewSize, Buffer, Res);
else
exit;
end;
Result := True;
end;
end;
function CryptoRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X: Integer;
Res: Integer;
begin
Result := False;
X := GetBits(StreamInfo.Option, 0, 5);
Res := 0;
Funcs^.GetResource(StreamInfo.Resource, nil, @Res);
Buffer := Funcs^.Allocator(Instance, Res);
if Funcs^.GetResource(StreamInfo.Resource, Buffer, @Res) then
begin
case X of
XOR_CODEC:
Funcs^.Encrypt('xor', Input, StreamInfo.NewSize, Buffer, Res);
AES_CODEC:
Funcs^.Encrypt('aes', Input, StreamInfo.NewSize, Buffer, Res);
RC4_CODEC:
Funcs^.Encrypt('rc4', Input, StreamInfo.NewSize, Buffer, Res);
else
exit;
end;
Output(Instance, Input, StreamInfo.OldSize);
Result := True;
end;
end;
var
I: Integer;
initialization
Codec.Names := [];
for I := Low(CryptoCodecs) to High(CryptoCodecs) do
begin
Codec.Names := Codec.Names + [CryptoCodecs[I]];
StockMethods.Add(CryptoCodecs[I]);
end;
Codec.Initialised := False;
Codec.Init := @CryptoInit;
Codec.Free := @CryptoFree;
Codec.Parse := @CryptoParse;
Codec.Scan1 := @CryptoScan1;
Codec.Scan2 := @CryptoScan2;
Codec.Process := @CryptoProcess;
Codec.Restore := @CryptoRestore;
end.

View File

@@ -0,0 +1,408 @@
unit PrecompDLL;
interface
uses
Utils,
PrecompUtils,
WinAPI.Windows,
System.SysUtils, System.Classes, System.StrUtils,
System.Types, System.Math, System.IOUtils;
var
Codec: TPrecompressor;
implementation
uses
PrecompMain;
type
LStrInfo1 = ^TStrInfo1;
TStrInfo1 = packed record
Position: Int64;
OldSize, NewSize: Integer;
Resource: Integer;
Option: Word;
end;
LStrInfo2 = ^TStrInfo2;
TStrInfo2 = packed record
OldSize, NewSize: Integer;
Resource: Integer;
Option: Word;
end;
LStrInfo3 = ^TStrInfo3;
TStrInfo3 = packed record
OldSize, NewSize, ExtSize: Integer;
Resource: Integer;
Option: Word;
end;
LPrecompFuncs = PPrecompFuncs;
TPrecompFuncs = _PrecompFuncs;
TPrecompOutput = procedure(Instance: Integer; const Buffer: Pointer;
Size: Integer)cdecl;
TPrecompAdd = procedure(Instance: Integer; Info: LStrInfo1; Codec: PChar;
DepthInfo: PDepthInfo)cdecl;
TPrecompInit = function(Command: PChar; Count: Integer; Funcs: LPrecompFuncs)
: Boolean cdecl;
TPrecompFree = procedure(Funcs: LPrecompFuncs)cdecl;
TPrecompCodec = function(Index: Integer): PChar cdecl;
TPrecompScan1 = procedure(Instance: Integer; Input: Pointer;
Size, SizeEx: NativeInt; Output: TPrecompOutput; Add: TPrecompAdd;
Funcs: LPrecompFuncs)cdecl;
TPrecompScan2 = function(Instance: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: LStrInfo2; Output: TPrecompOutput; Funcs: LPrecompFuncs)
: Boolean cdecl;
TPrecompProcess = function(Instance: Integer; OldInput, NewInput: Pointer;
StreamInfo: LStrInfo2; Output: TPrecompOutput; Funcs: LPrecompFuncs)
: Boolean cdecl;
TPrecompRestore = function(Instance: Integer; Input, InputExt: Pointer;
StreamInfo: TStrInfo3; Output: TPrecompOutput; Funcs: LPrecompFuncs)
: Boolean cdecl;
type
PDLLStruct = ^TDLLStruct;
TDLLStruct = record
Names: TArray<String>;
Init: TPrecompInit;
Free: TPrecompFree;
Codec: TPrecompCodec;
Scan1: TPrecompScan1;
Scan2: TPrecompScan2;
Process: TPrecompProcess;
Restore: TPrecompRestore;
end;
var
CodecIndex: TArray<Integer>;
CodecAdd: TArray<_PrecompAdd>;
DLLList: TStringDynArray;
CodecDLL: TArray<TDLLStruct>;
procedure AddStream(Instance: Integer; Info: LStrInfo1; Codec: PChar;
DepthInfo: PDepthInfo)cdecl;
var
SI: _StrInfo1;
begin
SI.Position := Info^.Position;
SI.OldSize := Info^.OldSize;
SI.NewSize := Info^.NewSize;
SI.Resource := Info^.Resource;
if System.Pos(SPrecompSep2, Codec) > 0 then
SI.Status := TStreamStatus.Predicted
else
SI.Status := TStreamStatus.None;
LongRec(SI.Option).Lo := Info^.Option;
LongRec(SI.Option).Hi := CodecIndex[Instance];
CodecAdd[Instance](Instance, @SI, Codec, DepthInfo)
end;
function DLLInit(Command: PChar; Count: Integer; Funcs: PPrecompFuncs): Boolean;
var
I, X: Integer;
S: String;
Used: Boolean;
begin
SetLength(CodecIndex, Count);
SetLength(CodecAdd, Count);
for I := High(CodecDLL) downto Low(CodecDLL) do
begin
Used := False;
X := 0;
while (Used = False) and (Funcs^.GetCodec(Command, X, False) <> '') do
begin
Used := IndexText(Funcs^.GetCodec(Command, X, False),
CodecDLL[I].Names) >= 0;
Inc(X);
end;
for X := 0 to ExternalMethods.Count - 1 do
if not Used then
Used := IndexText(ExternalMethods[X], CodecDLL[I].Names) >= 0;
S := Command;
if (Used = False) or (CodecDLL[I].Init(PChar(S), Count, @PrecompFunctions)
= False) then
Delete(CodecDLL, I, 1);
end;
Result := Length(CodecDLL) > 0;
end;
procedure DLLFree(Funcs: PPrecompFuncs);
var
I: Integer;
begin
for I := Low(CodecDLL) to High(CodecDLL) do
begin
if Assigned(CodecDLL[I].Free) then
CodecDLL[I].Free(@PrecompFunctions);
end;
end;
function DLLParse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
var
I: Integer;
begin
Result := False;
for I := Low(CodecDLL) to High(CodecDLL) do
begin
if IndexText(Funcs^.GetCodec(Command, 0, False), CodecDLL[I].Names) >= 0
then
begin
LongRec(Option^).Hi := I;
Result := True;
break;
end;
end;
end;
procedure DLLScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
var
I: Integer;
begin
for I := Low(CodecDLL) to High(CodecDLL) do
begin
try
CodecIndex[Instance] := I;
CodecAdd[Instance] := Add;
if Assigned(CodecDLL[I].Scan1) then
CodecDLL[I].Scan1(Instance, Input, Size, SizeEx, TPrecompOutput(Output),
@AddStream, @PrecompFunctions);
except
end;
end;
end;
function DLLScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
SI: TStrInfo2;
begin
Result := False;
SI.OldSize := StreamInfo^.OldSize;
SI.NewSize := StreamInfo^.NewSize;
SI.Resource := StreamInfo^.Resource;
SI.Option := LongRec(StreamInfo^.Option).Lo;
if Assigned(CodecDLL[LongRec(StreamInfo^.Option).Hi].Scan2) then
Result := CodecDLL[LongRec(StreamInfo^.Option).Hi].Scan2(Instance, Input,
Size, @SI, TPrecompOutput(Output), @PrecompFunctions);
if Result then
begin
StreamInfo^.OldSize := SI.OldSize;
StreamInfo^.NewSize := SI.NewSize;
StreamInfo^.Resource := SI.Resource;
LongRec(StreamInfo^.Option).Lo := SI.Option;
end;
end;
function DLLProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
SI: TStrInfo2;
begin
Result := False;
SI.OldSize := StreamInfo^.OldSize;
SI.NewSize := StreamInfo^.NewSize;
SI.Resource := StreamInfo^.Resource;
SI.Option := LongRec(StreamInfo^.Option).Lo;
if Assigned(CodecDLL[LongRec(StreamInfo^.Option).Hi].Process) then
Result := CodecDLL[LongRec(StreamInfo^.Option).Hi].Process(Instance,
OldInput, NewInput, @SI, TPrecompOutput(Output), @PrecompFunctions);
if Result then
begin
StreamInfo^.OldSize := SI.OldSize;
StreamInfo^.NewSize := SI.NewSize;
StreamInfo^.Resource := SI.Resource;
LongRec(StreamInfo^.Option).Lo := SI.Option;
end;
end;
function DLLRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
SI: TStrInfo3;
begin
Result := False;
SI.OldSize := StreamInfo.OldSize;
SI.NewSize := StreamInfo.NewSize;
SI.ExtSize := StreamInfo.ExtSize;
SI.Resource := StreamInfo.Resource;
SI.Option := LongRec(StreamInfo.Option).Lo;
if Assigned(CodecDLL[LongRec(StreamInfo.Option).Hi].Restore) then
Result := CodecDLL[LongRec(StreamInfo.Option).Hi].Restore(Instance, Input,
InputExt, SI, TPrecompOutput(Output), @PrecompFunctions);
end;
type
PIMAGE_NT_HEADERS = ^IMAGE_NT_HEADERS;
PIMAGE_EXPORT_DIRECTORY = ^IMAGE_EXPORT_DIRECTORY;
function ImageNtHeader(Base: Pointer): PIMAGE_NT_HEADERS; stdcall;
external 'dbghelp.dll';
function ImageRvaToVa(NtHeaders: Pointer; Base: Pointer; Rva: ULONG;
LastRvaSection: Pointer): Pointer; stdcall; external 'dbghelp.dll';
procedure ImageExportedFunctionNames(const ImageName: string;
NamesList: TStrings);
var
I: Integer;
FileHandle: THandle;
ImageHandle: THandle;
ImagePointer: Pointer;
Header: PIMAGE_NT_HEADERS;
ExportTable: PIMAGE_EXPORT_DIRECTORY;
NamesPointer: Pointer;
Names: PAnsiChar;
NamesDataLeft: Integer;
begin
// NOTE: our policy in this procedure is to exit upon any failure and return an empty list
NamesList.Clear;
FileHandle := CreateFile(PChar(ImageName), GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if FileHandle = INVALID_HANDLE_VALUE then
begin
exit;
end;
try
ImageHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil);
if ImageHandle = 0 then
begin
exit;
end;
try
ImagePointer := MapViewOfFile(ImageHandle, FILE_MAP_READ, 0, 0, 0);
if not Assigned(ImagePointer) then
begin
exit;
end;
try
Header := ImageNtHeader(ImagePointer);
if not Assigned(Header) then
begin
exit;
end;
if Header.Signature <> $00004550 then
begin // "PE\0\0" as a DWORD.
exit;
end;
ExportTable := ImageRvaToVa(Header, ImagePointer,
Header.OptionalHeader.DataDirectory[0].VirtualAddress, nil);
if not Assigned(ExportTable) then
begin
exit;
end;
NamesPointer := ImageRvaToVa(Header, ImagePointer,
Cardinal(ExportTable.AddressOfNames), nil);
if not Assigned(NamesPointer) then
begin
exit;
end;
Names := ImageRvaToVa(Header, ImagePointer,
Cardinal(NamesPointer^), nil);
if not Assigned(Names) then
begin
exit;
end;
NamesDataLeft := Header.OptionalHeader.DataDirectory[0].Size;
for I := 0 to ExportTable.NumberOfNames - 1 do
begin
NamesList.Add(Names);
// Locate the next name
while (Names^ <> chr(0)) and (NamesDataLeft > 0) do
begin
Inc(Names);
dec(NamesDataLeft);
end;
Inc(Names);
end;
finally
UnmapViewOfFile(ImagePointer);
// Ignore error as there is not much we could do.
end;
finally
CloseHandle(ImageHandle);
end;
finally
CloseHandle(FileHandle);
end;
end;
var
I, J: Integer;
S: String;
FuncList: TStringList;
DLLStruct: PDLLStruct;
DLLHandle: THandle;
initialization
DLLList := TDirectory.GetFiles(ExtractFilePath(Utils.GetModuleName), '*.dll',
TSearchOption.soTopDirectoryOnly);
FuncList := TStringList.Create;
for I := Low(DLLList) to High(DLLList) do
begin
ImageExportedFunctionNames(DLLList[I], FuncList);
if (FuncList.IndexOf('PrecompInit') >= 0) and
(FuncList.IndexOf('PrecompCodec') >= 0) then
begin
New(DLLStruct);
DLLHandle := LoadLibrary(PChar(DLLList[I]));
if DLLHandle >= 32 then
begin
@DLLStruct^.Init := GetProcAddress(DLLHandle, 'PrecompInit');
Assert(@DLLStruct^.Init <> nil);
@DLLStruct^.Free := GetProcAddress(DLLHandle, 'PrecompFree');
@DLLStruct^.Codec := GetProcAddress(DLLHandle, 'PrecompCodec');
@DLLStruct^.Scan1 := GetProcAddress(DLLHandle, 'PrecompScan1');
@DLLStruct^.Scan2 := GetProcAddress(DLLHandle, 'PrecompScan2');
@DLLStruct^.Process := GetProcAddress(DLLHandle, 'PrecompProcess');
@DLLStruct^.Restore := GetProcAddress(DLLHandle, 'PrecompRestore');
Insert(DLLStruct^, CodecDLL, Length(CodecDLL));
J := 0;
while Assigned(CodecDLL[Pred(Length(CodecDLL))].Codec(J)) do
begin
S := String(CodecDLL[Pred(Length(CodecDLL))].Codec(J));
Insert(S, CodecDLL[Pred(Length(CodecDLL))].Names,
Length(CodecDLL[Pred(Length(CodecDLL))].Names));
Insert(S, Codec.Names, Length(Codec.Names));
Inc(J);
end;
if J = 0 then
begin
Insert(ChangeFileExt(ExtractFileName(DLLList[I]), ''),
CodecDLL[Pred(Length(CodecDLL))].Names,
Length(CodecDLL[Pred(Length(CodecDLL))].Names));
Insert(ChangeFileExt(ExtractFileName(DLLList[I]), ''), Codec.Names,
Length(Codec.Names));
end;
end;
end;
end;
Codec.Initialised := False;
Codec.Init := @DLLInit;
Codec.Free := @DLLFree;
Codec.Parse := @DLLParse;
Codec.Scan1 := @DLLScan1;
Codec.Scan2 := @DLLScan2;
Codec.Process := @DLLProcess;
Codec.Restore := @DLLRestore;
end.

View File

@@ -0,0 +1,472 @@
unit PrecompExe;
interface
uses
Utils, SynCommons, SynCrypto,
PrecompUtils,
WinAPI.Windows,
System.SysUtils, System.Classes, System.StrUtils,
System.Types, System.Math, System.IOUtils, System.IniFiles;
const
FILE_IN = 'data.in';
FILE_OUT = 'data.out';
FILE_RES = 'data.res';
FILE_STORE = 'data.tmp';
FILE_MODE = 0;
STDIN_MODE = 1;
STDOUT_MODE = 2;
STDIO_MODE = 3;
type
PExeStruct = ^TExeStruct;
TExeStruct = record
Name: String;
Exec, Param: array [0 .. 1] of String;
WorkDir: array of array [0 .. 1] of String;
Mode: array [0 .. 1] of Byte;
InFile, OutFile: String;
Continuous: Boolean;
Ctx: array of array [0 .. 1] of Pointer;
end;
var
Codec: TPrecompressor;
implementation
const
E_WORKMEM = 65536;
var
WrkMem: array of array [0 .. E_WORKMEM - 1] of Byte;
CodecSize: TArray<Integer>;
CodecOutput: TArray<_PrecompOutput>;
CodecAllocator: array of function(
Index: Integer; Size: Integer): Pointer cdecl;
CodecExe: TArray<TExeStruct>;
procedure ExecOutput1(Instance: Integer; const Buffer: Pointer;
Size: Integer)cdecl;
begin
CodecOutput[Instance](Instance, Buffer, Size);
Inc(CodecSize[Instance], Size);
end;
procedure ExecOutput2(Instance: Integer; const Buffer: Pointer;
Size: Integer)cdecl;
var
LBuffer: PByte;
begin
LBuffer := CodecAllocator[Instance](Instance, CodecSize[Instance] + Size);
Move(Buffer^, (LBuffer + CodecSize[Instance])^, Size);
Inc(CodecSize[Instance], Size);
end;
function ExeInit(Command: PChar; Count: Integer; Funcs: PPrecompFuncs): Boolean;
var
X, Y, Z: Integer;
begin
Result := True;
Randomize;
SetLength(WrkMem, Count);
SetLength(CodecSize, Count);
SetLength(CodecOutput, Count);
SetLength(CodecAllocator, Count);
for X := Low(CodecExe) to High(CodecExe) do
begin
SetLength(CodecExe[X].WorkDir, Count);
SetLength(CodecExe[X].Ctx, Count);
for Z := 0 to 1 do
for Y := Low(CodecSize) to High(CodecSize) do
begin
repeat
CodecExe[X].WorkDir[Y, Z] := IncludeTrailingBackSlash
(IncludeTrailingBackSlash(GetCurrentDir) + CodecExe[X].Name + '_' +
IntToHex(Random($FFFF), 4));
until DirectoryExists(CodecExe[X].WorkDir[Y, Z]) = False;
IncludeTrailingBackSlash(CodecExe[X].WorkDir[Y, Z]);
if CodecExe[X].Mode[Z] = STDIO_MODE then
begin
CodecExe[X].Ctx[Y, Z] := PrecompExecStdioInit(Y,
PChar(CodecExe[X].Exec[Z]), PChar(CodecExe[X].Param[Z]),
PChar(CodecExe[X].WorkDir[Y, Z]));
end;
end;
AddMethod(CodecExe[X].Name);
end;
end;
procedure ExeFree(Funcs: PPrecompFuncs);
var
X, Y, Z: Integer;
begin
for X := Low(CodecExe) to High(CodecExe) do
for Z := 0 to 1 do
for Y := Low(CodecSize) to High(CodecSize) do
begin
if DirectoryExists(CodecExe[X].WorkDir[Y, Z]) then
RemoveDir(CodecExe[X].WorkDir[Y, Z]);
PrecompExecStdioFree(CodecExe[X].Ctx[Y, Z]);
end;
end;
function ExeParse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
var
I: Integer;
begin
Result := False;
Option^ := 0;
for I := Low(CodecExe) to High(CodecExe) do
begin
if Funcs^.GetCodec(Command, 0, False) = CodecExe[I].Name then
begin
SetBits(Option^, I, 0, 24);
Result := True;
break;
end;
end;
end;
procedure ExeScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
begin
// maybe add feature later...
end;
function ExeScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
X, Y: Integer;
Executed: Boolean;
begin
Result := False;
Executed := False;
X := GetBits(StreamInfo^.Option, 0, 24);
CodecSize[Instance] := 0;
CodecOutput[Instance] := Output;
with CodecExe[X] do
begin
if not DirectoryExists(WorkDir[Instance, 0]) then
CreateDir(WorkDir[Instance, 0]);
DeleteFile(WorkDir[Instance, 0] + InFile);
DeleteFile(WorkDir[Instance, 0] + OutFile);
case Mode[0] of
FILE_MODE, STDOUT_MODE:
begin
with TFileStream.Create(WorkDir[Instance, 0] + InFile, fmCreate) do
try
WriteBuffer(Input^, StreamInfo^.OldSize);
finally
Free;
end;
if Mode[0] = FILE_MODE then
Executed := PrecompExec(PChar(Exec[0]), PChar(Param[0]),
PChar(WorkDir[Instance, 0]))
else
Executed := PrecompExecStdout(Instance, PChar(Exec[0]),
PChar(Param[0]), PChar(WorkDir[Instance, 0]), ExecOutput1);
end;
else
begin
if Mode[0] = STDIN_MODE then
Executed := PrecompExecStdin(PChar(Exec[0]), PChar(Param[0]),
PChar(WorkDir[Instance, 0]), Input, StreamInfo^.OldSize)
else
Executed := PrecompExecStdioProcess(Ctx[Instance, 0], Input,
StreamInfo^.OldSize, ExecOutput1, Continuous);
end;
end;
if Executed then
begin
case Mode[0] of
FILE_MODE, STDIN_MODE:
begin
with TFileStream.Create(WorkDir[Instance, 0] + OutFile,
fmShareDenyNone) do
try
Y := Read(WrkMem[Instance, 0], E_WORKMEM);
while Y > 0 do
begin
ExecOutput1(Instance, @WrkMem[Instance, 0], Y);
Y := Read(WrkMem[Instance, 0], E_WORKMEM);
end;
finally
Free;
end;
end;
end;
StreamInfo^.NewSize := CodecSize[Instance];
Result := True;
end;
end;
end;
function ExeProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X, Y: Integer;
Res1: Integer;
Res2: NativeUInt;
Executed: Boolean;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 24);
CodecSize[Instance] := 0;
CodecAllocator[Instance] := Funcs^.Allocator;
with CodecExe[X] do
begin
if not DirectoryExists(WorkDir[Instance, 1]) then
CreateDir(WorkDir[Instance, 1]);
DeleteFile(WorkDir[Instance, 1] + InFile);
DeleteFile(WorkDir[Instance, 1] + OutFile);
case Mode[1] of
FILE_MODE, STDOUT_MODE:
begin
with TFileStream.Create(WorkDir[Instance, 1] + OutFile, fmCreate) do
try
WriteBuffer(NewInput^, StreamInfo^.NewSize);
finally
Free;
end;
if Mode[1] = FILE_MODE then
Executed := PrecompExec(PChar(Exec[1]), PChar(Param[1]),
PChar(WorkDir[Instance, 1]))
else
Executed := PrecompExecStdout(Instance, PChar(Exec[1]),
PChar(Param[1]), PChar(WorkDir[Instance, 1]), ExecOutput2);
end;
else
begin
if Mode[1] = STDIN_MODE then
Executed := PrecompExecStdin(PChar(Exec[1]), PChar(Param[1]),
PChar(WorkDir[Instance, 1]), NewInput, StreamInfo^.NewSize)
else
Executed := PrecompExecStdioProcess(Ctx[Instance, 1], NewInput,
StreamInfo^.NewSize, ExecOutput2, Continuous);
end;
end;
if Executed then
begin
case Mode[1] of
FILE_MODE, STDIN_MODE:
begin
with TFileStream.Create(WorkDir[Instance, 1] + InFile,
fmShareDenyNone) do
try
Y := Read(WrkMem[Instance, 0], E_WORKMEM);
while Y > 0 do
begin
ExecOutput2(Instance, @WrkMem[Instance, 0], Y);
Y := Read(WrkMem[Instance, 0], E_WORKMEM);
end;
finally
Free;
end;
end;
end;
Buffer := Funcs^.Allocator(Instance, CodecSize[Instance]);
Res1 := CodecSize[Instance];
Result := (Res1 = StreamInfo^.OldSize) and CompareMem(OldInput, Buffer,
StreamInfo^.OldSize);
if Result = False then
begin
Buffer := Funcs^.Allocator(Instance,
Res1 + Max(StreamInfo^.OldSize, Res1));
Res2 := PrecompEncodePatch(OldInput, StreamInfo^.OldSize, Buffer, Res1,
Buffer + Res1, Max(StreamInfo^.OldSize, Res1));
if (Res2 > 0) and ((Res2 / Max(StreamInfo^.OldSize, Res1)) <=
DIFF_TOLERANCE) then
begin
Output(Instance, Buffer + Res1, Res2);
SetBits(StreamInfo^.Option, 1, 31, 1);
Result := True;
end;
end;
end;
end;
end;
function ExeRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X, Y: Integer;
Res1: Integer;
Res2: NativeUInt;
Executed: Boolean;
begin
Result := False;
X := GetBits(StreamInfo.Option, 0, 24);
CodecSize[Instance] := 0;
CodecAllocator[Instance] := Funcs^.Allocator;
with CodecExe[X] do
begin
if not DirectoryExists(WorkDir[Instance, 1]) then
CreateDir(WorkDir[Instance, 1]);
DeleteFile(WorkDir[Instance, 1] + InFile);
DeleteFile(WorkDir[Instance, 1] + OutFile);
case Mode[1] of
FILE_MODE, STDOUT_MODE:
begin
with TFileStream.Create(WorkDir[Instance, 1] + OutFile, fmCreate) do
try
WriteBuffer(Input^, StreamInfo.NewSize);
finally
Free;
end;
if Mode[1] = FILE_MODE then
Executed := PrecompExec(PChar(Exec[1]), PChar(Param[1]),
PChar(WorkDir[Instance, 1]))
else
Executed := PrecompExecStdout(Instance, PChar(Exec[1]),
PChar(Param[1]), PChar(WorkDir[Instance, 1]), ExecOutput2);
end;
else
begin
if Mode[1] = STDIN_MODE then
Executed := PrecompExecStdin(PChar(Exec[1]), PChar(Param[1]),
PChar(WorkDir[Instance, 1]), Input, StreamInfo.NewSize)
else
Executed := PrecompExecStdioProcess(Ctx[Instance, 1], Input,
StreamInfo.NewSize, ExecOutput2, Continuous);
end;
end;
if Executed then
begin
case Mode[1] of
FILE_MODE, STDIN_MODE:
begin
with TFileStream.Create(WorkDir[Instance, 1] + InFile,
fmShareDenyNone) do
try
Y := Read(WrkMem[Instance, 0], E_WORKMEM);
while Y > 0 do
begin
ExecOutput2(Instance, @WrkMem[Instance, 0], Y);
Y := Read(WrkMem[Instance, 0], E_WORKMEM);
end;
finally
Free;
end;
end;
end;
Buffer := Funcs^.Allocator(Instance, CodecSize[Instance]);
Res1 := CodecSize[Instance];
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);
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;
end;
end;
var
I, J, X: Integer;
S1, S2: String;
Ini: TMemIniFile;
SL: TStringList;
ExeStruct: PExeStruct;
initialization
S1 := ChangeFileExt(Utils.GetModuleName, '.ini');
if FileExists(S1) then
begin
Ini := TMemIniFile.Create(S1);
SL := TStringList.Create;
Ini.ReadSections(SL);
for I := 0 to SL.Count - 1 do
if FileExists(ExtractFilePath(Utils.GetModuleName) +
GetCmdStr(Ini.ReadString(SL[I], 'Encode', ''), 0)) then
begin
New(ExeStruct);
Insert(SL[I], Codec.Names, Length(Codec.Names));
ExeStruct^.Name := SL[I];
ExeStruct^.Continuous := Ini.ReadBool(SL[I], 'Continous', False);
for X := 0 to 1 do
begin
if X = 0 then
S1 := Ini.ReadString(SL[I], 'Encode', '')
else
S1 := Ini.ReadString(SL[I], 'Decode', '');
ExeStruct^.Exec[X] := ExtractFilePath(Utils.GetModuleName) +
GetCmdStr(S1, 0);
ExeStruct^.Param[X] := '';
ExeStruct^.Mode[X] := 0;
for J := 1 to GetCmdCount(S1) do
begin
S2 := GetCmdStr(S1, J);
if ContainsText(S2, '<stdin>') then
begin
SetBits(ExeStruct^.Mode[X], 1, 0, 1);
continue;
end
else if ContainsText(S2, '<stdout>') then
begin
SetBits(ExeStruct^.Mode[X], 1, 1, 1);
continue;
end
else if ContainsText(S2, '<filein>') or ContainsText(S2, '[filein]')
then
begin
SetBits(ExeStruct^.Mode[X], 0, 0, 1);
ExeStruct^.InFile := S2;
ExeStruct^.InFile := ReplaceStr(ExeStruct^.InFile,
'<filein>', FILE_IN);
ExeStruct^.InFile := ReplaceStr(ExeStruct^.InFile,
'[filein]', FILE_IN);
if ContainsText(S2, '[filein]') then
continue;
end
else if ContainsText(S2, '<fileout>') or ContainsText(S2, '[fileout]')
then
begin
SetBits(ExeStruct^.Mode[X], 0, 1, 1);
ExeStruct^.OutFile := S2;
ExeStruct^.OutFile := ReplaceStr(ExeStruct^.OutFile, '<fileout>',
FILE_OUT);
ExeStruct^.OutFile := ReplaceStr(ExeStruct^.OutFile, '[fileout]',
FILE_OUT);
if ContainsText(S2, '[fileout]') then
continue;
end;
S2 := IfThen(Pos(' ', S2) > 0, '"' + S2 + '"', S2);
ExeStruct^.Param[X] := ExeStruct^.Param[X] + ' ' + S2;
end;
ExeStruct^.Param[X] := Trim(ExeStruct^.Param[X]);
end;
Insert(ExeStruct^, CodecExe, Length(CodecExe));
end;
SL.Free;
Ini.Free;
end;
Codec.Initialised := False;
Codec.Init := @ExeInit;
Codec.Free := @ExeFree;
Codec.Parse := @ExeParse;
Codec.Scan1 := @ExeScan1;
Codec.Scan2 := @ExeScan2;
Codec.Process := @ExeProcess;
Codec.Restore := @ExeRestore;
end.

View File

@@ -0,0 +1,512 @@
unit PrecompINI;
interface
uses
Utils, ParseExpr,
PrecompUtils,
WinAPI.Windows,
System.SysUtils, System.Classes, System.StrUtils,
System.Types, System.Math, System.IOUtils, System.IniFiles;
var
Codec: TPrecompressor;
implementation
type
PCfgStruct = ^TCfgStruct;
TCfgStruct = record
Name: String;
Data: Pointer;
Position, Size: NativeInt;
Value: Double;
BeforeStream: Boolean;
end;
PConfigRec = ^TConfigRec;
TConfigRec = record
Parser: TExpressionParser;
Name, Codec: String;
Resource: Integer;
BigEndian: Boolean;
Structure: TArray<TCfgStruct>;
StreamOffset, OldSize, NewSize: String;
Names, Exprs: TArray<String>;
Values: TArray<Double>;
Conditions: TArray<String>;
end;
PCfgRecDynArray = ^TCfgRecDynArray;
TCfgRecDynArray = TArray<TConfigRec>;
var
CfgList: TStringDynArray;
CodecCfg: TArray<TArray<TCfgRecDynArray>>;
CodecAvailable, CodecEnabled: TArray<TArray<Boolean>>;
procedure EndianMove(Source, Dest: Pointer; Size: NativeInt;
BigEndian: Boolean = False);
begin
if BigEndian then
ReverseBytes(Source, Dest, Size)
else
Move(Source^, Dest^, Size);
end;
function ConfigInit(Command: PChar; Count: Integer;
Funcs: PPrecompFuncs): Boolean;
var
I, J: Integer;
X, Y, Z: Integer;
S: String;
ParamsSet: Boolean;
begin
Result := True;
ParamsSet := False;
for X := Low(CodecAvailable) to High(CodecAvailable) do
for Y := Low(CodecAvailable[X]) to High(CodecAvailable[X]) do
begin
CodecAvailable[X, Y] := True;
CodecEnabled[X, Y] := False;
end;
SetLength(CodecCfg, Count);
for I := 1 to High(CodecCfg) do
begin
SetLength(CodecCfg[I], Length(CodecCfg[0]));
for J := Low(CodecCfg[I]) to High(CodecCfg[I]) do
SetLength(CodecCfg[I, J], Length(CodecCfg[0, J]));
end;
for I := Low(CodecCfg) to High(CodecCfg) do
for J := Low(CodecCfg[I]) to High(CodecCfg[I]) do
for X := Low(CodecCfg[I, J]) to High(CodecCfg[I, J]) do
with CodecCfg[I, J, X] do
begin
if I = 0 then
Resource := RegisterResources(Codec);
if I > 0 then
begin
Parser := TExpressionParser.Create;
Name := CodecCfg[0, J, X].Name;
Codec := CodecCfg[0, J, X].Codec;
Resource := CodecCfg[0, J, X].Resource;
BigEndian := CodecCfg[0, J, X].BigEndian;
SetLength(Structure, Length(CodecCfg[0, J, X].Structure));
for Y := Low(Structure) to High(Structure) do
begin
Structure[Y].Name := CodecCfg[0, J, X].Structure[Y].Name;
Structure[Y].Position := CodecCfg[0, J, X].Structure[Y].Position;
Structure[Y].Size := CodecCfg[0, J, X].Structure[Y].Size;
Structure[Y].Value := CodecCfg[0, J, X].Structure[Y].Value;
Structure[Y].BeforeStream := CodecCfg[0, J, X].Structure[Y]
.BeforeStream;
GetMem(Structure[Y].Data, Structure[Y].Size);
Move(CodecCfg[0, J, X].Structure[Y].Data^, Structure[Y].Data^,
Structure[Y].Size);
end;
StreamOffset := CodecCfg[0, J, X].StreamOffset;
OldSize := CodecCfg[0, J, X].OldSize;
NewSize := CodecCfg[0, J, X].NewSize;
SetLength(Names, Length(CodecCfg[0, J, X].Names));
SetLength(Exprs, Length(CodecCfg[0, J, X].Exprs));
SetLength(Values, Length(CodecCfg[0, J, X].Values));
for Y := Low(Names) to High(Names) do
begin
Names[Y] := CodecCfg[0, J, X].Names[Y];
Exprs[Y] := CodecCfg[0, J, X].Exprs[Y];
Values[Y] := CodecCfg[0, J, X].Values[Y];
end;
SetLength(Conditions, Length(CodecCfg[0, J, X].Conditions));
for Y := Low(Conditions) to High(Conditions) do
Conditions[Y] := CodecCfg[0, J, X].Conditions[Y];
for Y := Low(Names) to High(Names) do
Parser.DefineVariable(Names[Y], @Values[Y]);
for Y := Low(Structure) to High(Structure) do
Parser.DefineVariable(Structure[Y].Name, @Structure[Y].Value);
end;
end;
X := 0;
while Funcs^.GetCodec(Command, X, False) <> '' do
begin
S := Funcs^.GetCodec(Command, X, False);
for Y := Low(Codec.Names) to High(Codec.Names) do
if CompareText(S, Codec.Names[Y]) = 0 then
begin
for I := Low(CodecEnabled[Y]) to High(CodecEnabled[Y]) do
CodecEnabled[Y][I] := True;
for Z := Low(CodecCfg[0, Y]) to High(CodecCfg[0, Y]) do
if Funcs^.GetParam(Command, X, PChar(CodecCfg[0, Y, Z].Name)) <> ''
then
begin
if not ParamsSet then
begin
for I := Low(CodecEnabled[Y]) to High(CodecEnabled[Y]) do
CodecEnabled[Y][I] := False;
ParamsSet := True;
end;
CodecEnabled[Y, Z] := True;
end;
break;
end;
Inc(X);
end;
for X := Low(CodecEnabled) to High(CodecEnabled) do
for Y := Low(CodecEnabled[X]) to High(CodecEnabled[X]) do
if CodecEnabled[X, Y] then
AddMethod(PrecompGetCodec(PChar(CodecCfg[0, X, Y].Codec), 0, False));
end;
procedure ConfigFree(Funcs: PPrecompFuncs);
var
I, J: Integer;
X, Y: Integer;
begin
for I := Low(CodecCfg) to High(CodecCfg) do
for J := Low(CodecCfg[I]) to High(CodecCfg[I]) do
for X := Low(CodecCfg[I, J]) to High(CodecCfg[I, J]) do
with CodecCfg[I, J, X] do
begin
if I > 0 then
begin
for Y := Low(Structure) to High(Structure) do
FreeMem(Structure[Y].Data);
end;
end;
end;
function ConfigParse(Command: String; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
begin
Result := False;
end;
procedure ConfigScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
type
TScanStatus = (None, Success, Fail);
var
Status: TScanStatus;
A, B: Integer;
I, J: Integer;
X, Y: Integer;
Pos: NativeInt;
NI: NativeInt;
I64: Int64;
StreamPosInt, StreamOffsetInt, OldSizeInt, NewSizeInt: NativeInt;
SI: _StrInfo1;
begin
for I := Low(CodecCfg[Instance]) to High(CodecCfg[Instance]) do
for J := Low(CodecCfg[Instance, I]) to High(CodecCfg[Instance, I]) do
if CodecEnabled[I, J] then
with CodecCfg[Instance, I, J] do
for X := Low(Structure) to High(Structure) do
if Structure[X].Name = 'Signature' then
begin
Pos := 0;
while BinarySearch(Input, Pos, Size, Structure[X].Data,
Structure[X].Size, Pos) do
begin
Status := TScanStatus.None;
StreamPosInt := Pos;
for Y := Low(Structure) to High(Structure) do
begin
if (X <> Y) and (Structure[Y].BeforeStream = True) then
begin
NI := Structure[Y].Position - Structure[X].Position;
if Structure[Y].Name = 'Stream' then
begin
StreamPosInt := Pos + NI;
continue;
end;
if InRange(Pos + NI, 0, SizeEx - Structure[Y].Size) then
begin
Move((Input + Pos + NI)^, Structure[Y].Data^,
Structure[Y].Size);
I64 := 0;
EndianMove(Structure[Y].Data, @I64,
Min(Structure[Y].Size, I64.Size), BigEndian);
Structure[Y].Value := I64.ToDouble;
end
else
Status := TScanStatus.Fail;
end;
if Status = TScanStatus.Fail then
break;
end;
if Status = TScanStatus.Fail then
begin
Inc(Pos);
continue;
end;
for A := Low(Exprs) to High(Exprs) do
begin
for B := Low(Exprs) to High(Exprs) do
try
if A = B then
continue;
Values[B] := Parser.Evaluate(Exprs[B]);
except
end;
try
Values[A] := Parser.Evaluate(Exprs[A]);
except
end;
end;
StreamOffsetInt := Round(Parser.Evaluate(StreamOffset));
OldSizeInt := Round(Parser.Evaluate(OldSize));
NewSizeInt := Round(Parser.Evaluate(NewSize));
for Y := Low(Structure) to High(Structure) do
begin
if (X <> Y) and (Structure[Y].BeforeStream = False) then
begin
NI := Structure[Y].Position - Structure[X].Position +
StreamOffsetInt + OldSizeInt;
if InRange(Pos + NI, 0, SizeEx - Structure[Y].Size) then
begin
Move((Input + Pos + NI)^, Structure[Y].Data^,
Structure[Y].Size);
I64 := 0;
EndianMove(Structure[Y].Data, @I64,
Min(Structure[Y].Size, I64.Size), BigEndian);
Structure[Y].Value := I64.ToDouble;
end
else
Status := TScanStatus.Fail;
end;
if Status = TScanStatus.Fail then
break;
end;
for Y := Low(Conditions) to High(Conditions) do
begin
if Round(Parser.Evaluate(Conditions[Y])) = 0 then
break;
end;
if (Length(Conditions) = 0) or (Y = High(Conditions)) then
begin
Output(Instance, nil, -1);
SI.Position := StreamPosInt + StreamOffsetInt;
SI.OldSize := OldSizeInt;
SI.NewSize := NewSizeInt;
SI.Resource := Resource;
SI.Option := 0;
if System.Pos(SPrecompSep2, Codec) > 0 then
SI.Status := TStreamStatus.Predicted
else
SI.Status := TStreamStatus.None;
Add(Instance, @SI, PChar(Codec), nil);
Inc(Pos, Max(OldSizeInt, 1));
// fix this
Status := TScanStatus.Success;
end;
if Status <> TScanStatus.Success then
Inc(Pos);
end;
end;
end;
function ConfigScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
begin
Result := False;
end;
function ConfigProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
begin
Result := False;
end;
function ConfigRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
begin
Result := False;
end;
procedure DecodeHeader(const Header: String; out Name, Value: String);
begin
if (Pos('(', Header) > 0) and (Pos(')', Header) > 0) then
begin
Name := ReplaceStr(Header.Substring(0, Header.IndexOf('(')), ' ', '');
Value := Header.Substring(Succ(Header.IndexOf('(')),
Header.IndexOf(')') - Succ(Header.IndexOf('(')));
end
else
Name := Header;
end;
procedure ConvertHexChr(var S: String);
begin
S := ReplaceStr(S, '0x', '$');
S := ReplaceStr(S, '#', '$');
end;
var
I, J, X, Y: Integer;
SL: TStringList;
Bytes: TBytes;
S1, S2: String;
Pos: Integer;
BStream: Boolean;
HexValue: Boolean;
CfgRec: PConfigRec;
CfgRecArray: PCfgRecDynArray;
CfgStruct: PCfgStruct;
SList: TStringDynArray;
PStr1: PAnsiChar;
PStr2: PString;
initialization
CfgList := TDirectory.GetFiles(ExtractFilePath(Utils.GetModuleName), '*.ini',
TSearchOption.soTopDirectoryOnly);
SL := TStringList.Create;
SetLength(CodecCfg, 1);
for I := Low(CfgList) to High(CfgList) do
begin
with TIniFile.Create(CfgList[I]) do
try
if ReadString('Stream1', 'Name', '') <> '' then
begin
S1 := ChangeFileExt(ExtractFileName(CfgList[I]), '');
Insert(S1, Codec.Names, Length(Codec.Names));
New(CfgRecArray);
X := 1;
while ReadString('Stream' + X.ToString, 'Name', '') <> '' do
begin
New(CfgRec);
CfgRec^.Parser := TExpressionParser.Create;
CfgRec^.Name := ReadString('Stream' + X.ToString, 'Name', '');
CfgRec^.Codec := ReadString('Stream' + X.ToString, 'Codec', '');
CfgRec^.BigEndian := ReadBool('Stream' + X.ToString,
'BigEndian', False);
SList := DecodeStr(ReadString('Stream' + X.ToString, 'Structure',
''), ',');
Pos := 0;
BStream := True;
for Y := Low(SList) to High(SList) do
begin
New(CfgStruct);
DecodeHeader(SList[Y], S1, S2);
ConvertHexChr(S2);
CfgStruct^.Name := S1;
CfgStruct^.Size :=
Round(IfThen(S2 <> '', CfgRec^.Parser.Evaluate(S2), 0));
GetMem(CfgStruct^.Data, CfgStruct^.Size);
if CfgStruct^.Name = 'Signature' then
begin
S1 := ReplaceStr(ReadString('Stream' + X.ToString, 'Signature',
'0'), ' ', '');
ConvertHexChr(S1);
HexValue := S1[1] = '$';
if HexValue then
begin
S1 := S1.Substring(1);
SetLength(Bytes, CfgStruct^.Size);
SetLength(Bytes, HexToBin(BytesOf(S1), 0, Bytes, 0,
Length(Bytes)));
if CfgRec^.BigEndian then
Move(Bytes[0], CfgStruct^.Data^, CfgStruct^.Size)
else
ReverseBytes(@Bytes[0], CfgStruct^.Data, CfgStruct^.Size);
end
else
begin
Bytes := BytesOf(S1);
SetLength(Bytes, CfgStruct^.Size);
Move(Bytes[0], CfgStruct^.Data^, CfgStruct^.Size);
end;
end;
CfgStruct^.Position := Pos;
CfgStruct^.Value := 0;
CfgStruct^.BeforeStream := BStream;
if (CfgStruct^.Name = 'Stream') or (CfgStruct^.Size > 0) then
Insert(CfgStruct^, CfgRec^.Structure, Length(CfgRec^.Structure));
Inc(Pos, CfgStruct^.Size);
if CfgStruct^.Name = 'Stream' then
begin
Pos := 0;
BStream := False;
end;
end;
CfgRec^.StreamOffset := ReadString('Stream' + X.ToString,
'StreamOffset', '0');
ConvertHexChr(CfgRec^.StreamOffset);
CfgRec^.OldSize := ReadString('Stream' + X.ToString,
'CompressedSize', '0');
ConvertHexChr(CfgRec^.OldSize);
CfgRec^.NewSize := ReadString('Stream' + X.ToString,
'DecompressedSize', '0');
ConvertHexChr(CfgRec^.NewSize);
Y := 1;
while ReadString('Stream' + X.ToString, 'Condition' + Y.ToString,
'') <> '' do
begin
New(PStr2);
PStr2^ := ReadString('Stream' + X.ToString,
'Condition' + Y.ToString, '');
ConvertHexChr(PStr2^);
Insert(PStr2^, CfgRec^.Conditions, Length(CfgRec^.Conditions));
Inc(Y);
end;
ReadSectionValues('Stream' + X.ToString, SL);
for J := SL.Count - 1 downto 0 do
begin
S1 := SL[J].Substring(0, SL[J].IndexOf('=')).TrimRight;
S2 := SL[J].Substring(Succ(SL[J].IndexOf('='))).TrimLeft;
if (IndexText(S1, ['Name', 'Codec', 'BigEndian', 'Signature',
'Structure']) >= 0) or S1.StartsWith('Condition', True) then
SL.Delete(J);
end;
SetLength(CfgRec^.Names, SL.Count);
SetLength(CfgRec^.Exprs, SL.Count);
SetLength(CfgRec^.Values, SL.Count);
for J := 0 to SL.Count - 1 do
begin
S1 := SL[J].Substring(0, SL[J].IndexOf('=')).TrimRight;
S2 := SL[J].Substring(Succ(SL[J].IndexOf('='))).TrimLeft;
CfgRec^.Names[J] := S1;
CfgRec^.Exprs[J] := S2;
CfgRec^.Values[J] := 0;
end;
Insert(CfgRec^, CfgRecArray^, Length(CfgRecArray^));
Inc(X);
end;
Insert(CfgRecArray^, CodecCfg[0], Length(CodecCfg[0]));
end;
finally
Free;
end;
end;
for J := Low(CodecCfg[0]) to High(CodecCfg[0]) do
for X := Low(CodecCfg[0, J]) to High(CodecCfg[0, J]) do
begin
with CodecCfg[0, J, X] do
begin
for Y := Low(Names) to High(Names) do
Parser.DefineVariable(Names[Y], @Values[Y]);
for Y := Low(Structure) to High(Structure) do
Parser.DefineVariable(Structure[Y].Name, @Structure[Y].Value);
end;
end;
Codec.Initialised := False;
Codec.Init := @ConfigInit;
Codec.Free := @ConfigFree;
Codec.Parse := @ConfigParse;
Codec.Scan1 := @ConfigScan1;
Codec.Scan2 := @ConfigScan2;
Codec.Process := @ConfigProcess;
Codec.Restore := @ConfigRestore;
SetLength(CodecAvailable, Length(CodecCfg[0]));
SetLength(CodecEnabled, Length(CodecCfg[0]));
for I := Low(CodecCfg[0]) to High(CodecCfg[0]) do
begin
SetLength(CodecAvailable[I], Length(CodecCfg[0, I]));
SetLength(CodecEnabled[I], Length(CodecCfg[0, I]));
end;
end.

View File

@@ -0,0 +1,341 @@
unit PrecompLZ4;
interface
uses
LZ4DLL, XDeltaDLL,
Utils,
PrecompUtils,
System.SysUtils, System.StrUtils, System.Classes, System.Math;
var
Codec: TPrecompressor;
implementation
const
LZ4Codecs: array of PChar = ['lz4', 'lz4hc'];
CODEC_COUNT = 2;
LZ4_CODEC = 0;
LZ4HC_CODEC = 1;
const
L_MAXSIZE = 16 * 1024 * 1024;
var
SOList: array of array [0 .. CODEC_COUNT - 1] of TSOList;
CodecAvailable, CodecEnabled: TArray<Boolean>;
function LZ4Init(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] := LZ4DLL.DLLLoaded;
X := 0;
while Funcs^.GetCodec(Command, X, False) <> '' do
begin
S := Funcs^.GetCodec(Command, X, False);
if (CompareText(S, LZ4Codecs[LZ4_CODEC]) = 0) and LZ4DLL.DLLLoaded then
begin
CodecEnabled[LZ4_CODEC] := True;
SOList[I][LZ4_CODEC].Update([1], True);
end
else if (CompareText(S, LZ4Codecs[LZ4HC_CODEC]) = 0) and LZ4DLL.DLLLoaded
then
begin
CodecEnabled[LZ4HC_CODEC] := True;
if Funcs^.GetParam(Command, X, 'l') <> '' then
for I := Low(SOList) to High(SOList) do
SOList[I][LZ4HC_CODEC].Update
([StrToInt(Funcs^.GetParam(Command, X, 'l'))], True);
end;
Inc(X);
end;
SetLength(Options, 0);
for I := 3 to 12 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 LZ4Free(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 LZ4Parse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
var
S: String;
I: Integer;
begin
Result := False;
Option^ := 0;
I := 0;
while Funcs^.GetCodec(Command, I, False) <> '' do
begin
S := Funcs^.GetCodec(Command, I, False);
if (CompareText(S, LZ4Codecs[LZ4_CODEC]) = 0) and LZ4DLL.DLLLoaded then
begin
SetBits(Option^, 0, 0, 5);
Result := True;
end
else if (CompareText(S, LZ4Codecs[LZ4HC_CODEC]) = 0) and LZ4DLL.DLLLoaded
then
begin
SetBits(Option^, 1, 0, 5);
if Funcs^.GetParam(Command, I, 'l') <> '' then
SetBits(Option^, StrToInt(Funcs^.GetParam(Command, I, 'l')), 5, 7);
Result := True;
end;
Inc(I);
end;
end;
procedure LZ4Scan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
var
Buffer: PByte;
Pos: NativeInt;
LSize: NativeInt;
P: Integer;
Frame: Byte;
CSize, DSize: Integer;
SI: _StrInfo1;
DI: TDepthInfo;
DS: TPrecompCmd;
begin
if BoolArray(CodecEnabled, False) then
exit;
Buffer := Funcs^.Allocator(Instance, L_MAXSIZE);
Pos := 0;
LSize := Size - 11;
while Pos < LSize do
begin
if (PInteger(Input + Pos)^ = $184D2204) then
begin
P := 0;
Inc(P, 4);
Frame := PByte(Input + Pos + P)^;
if Frame = $64 then
begin
Inc(P, 3);
CSize := PInteger(Input + Pos + P)^;
Inc(P, 4);
DSize := LZ4_decompress_safe((Input + Pos + P), Buffer, CSize,
L_MAXSIZE);
if CSize > DSize then
begin
Inc(Pos);
continue;
end
else
begin
Output(Instance, Buffer, DSize);
SI.Position := Pos + P;
SI.OldSize := CSize;
SI.NewSize := DSize;
SI.Option := 0;
SI.Status := TStreamStatus.None;
Add(Instance, @SI, nil, nil);
Inc(Pos, P);
continue;
end;
end;
end;
Inc(Pos);
end;
DI := Funcs^.GetDepthInfo(Instance);
DS := Funcs^.GetCodec(DI.Codec, 0, False);
if DS <> '' then
begin
if IndexTextW(@DS[0], LZ4Codecs) < 0 then
exit;
end
else
exit;
if (DI.OldSize <> Size) or (DI.OldSize >= DI.NewSize) then
exit;
Buffer := Funcs^.Allocator(Instance, DI.NewSize);
DSize := LZ4_decompress_safe(Input, Buffer, Size, DI.NewSize);
if (DSize > DI.OldSize) then
begin
Output(Instance, Buffer, DSize);
SI.Position := 0;
SI.OldSize := DI.OldSize;
SI.NewSize := DSize;
SI.Option := 0;
if System.Pos(SPrecompSep2, DI.Codec) > 0 then
SI.Status := TStreamStatus.Predicted
else
SI.Status := TStreamStatus.None;
Add(Instance, @SI, DI.Codec, nil);
end;
end;
function LZ4Scan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X: Integer;
Res: Integer;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if StreamInfo^.NewSize <= 0 then
exit;
Buffer := Funcs^.Allocator(Instance, StreamInfo^.NewSize);
case X of
LZ4_CODEC, LZ4HC_CODEC:
Res := LZ4_decompress_safe(Input, Buffer, StreamInfo^.OldSize,
StreamInfo^.NewSize);
else
Res := LZ4_decompress_safe(Input, Buffer, StreamInfo^.OldSize,
StreamInfo^.NewSize);
end;
if Res = StreamInfo^.NewSize then
begin
StreamInfo^.NewSize := Res;
Output(Instance, Buffer, Res);
Result := True;
end;
end;
function LZ4Process(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer, Ptr: PByte;
I: Integer;
X: Integer;
Res1: Integer;
Res2: NativeUInt;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
Buffer := Funcs^.Allocator(Instance, 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;
case X of
LZ4_CODEC:
Res1 := LZ4_compress_default(NewInput, Buffer, StreamInfo^.NewSize,
StreamInfo^.NewSize);
LZ4HC_CODEC:
Res1 := LZ4_compress_HC(NewInput, Buffer, StreamInfo^.NewSize,
StreamInfo^.NewSize, I);
end;
Result := (Res1 = StreamInfo^.OldSize) and CompareMem(OldInput, Buffer,
StreamInfo^.OldSize);
if Result then
begin
SetBits(StreamInfo^.Option, I, 5, 7);
SOList[Instance][X].Add(I);
break;
end;
end;
if (Result = False) and ((StreamInfo^.Status = TStreamStatus.Predicted) or
(SOList[Instance][X].Count = 1)) then
begin
Buffer := Funcs^.Allocator(Instance, Res1 + Max(StreamInfo^.OldSize, Res1));
Res2 := PrecompEncodePatch(OldInput, StreamInfo^.OldSize, Buffer, Res1,
Buffer + Res1, Max(StreamInfo^.OldSize, Res1));
if (Res2 > 0) and ((Res2 / Max(StreamInfo^.OldSize, Res1)) <= DIFF_TOLERANCE)
then
begin
Output(Instance, Buffer + Res1, Res2);
SetBits(StreamInfo^.Option, 1, 31, 1);
SOList[Instance][X].Add(I);
Result := True;
end;
end;
end;
function LZ4Restore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X: Integer;
Res1: Integer;
Res2: NativeUInt;
begin
Result := False;
X := GetBits(StreamInfo.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
Buffer := Funcs^.Allocator(Instance, StreamInfo.NewSize);
case X of
LZ4_CODEC:
Res1 := LZ4_compress_default(Input, Buffer, StreamInfo.NewSize,
StreamInfo.NewSize);
LZ4HC_CODEC:
Res1 := LZ4_compress_HC(Input, Buffer, StreamInfo.NewSize,
StreamInfo.NewSize, GetBits(StreamInfo.Option, 5, 7));
end;
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);
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(LZ4Codecs) to High(LZ4Codecs) do
begin
Codec.Names := Codec.Names + [LZ4Codecs[I]];
StockMethods.Add(LZ4Codecs[I]);
end;
Codec.Initialised := False;
Codec.Init := @LZ4Init;
Codec.Free := @LZ4Free;
Codec.Parse := @LZ4Parse;
Codec.Scan1 := @LZ4Scan1;
Codec.Scan2 := @LZ4Scan2;
Codec.Process := @LZ4Process;
Codec.Restore := @LZ4Restore;
SetLength(CodecAvailable, Length(Codec.Names));
SetLength(CodecEnabled, Length(Codec.Names));
end.

View File

@@ -0,0 +1,374 @@
unit PrecompLZO;
interface
uses
LZODLL, XDeltaDLL,
Utils,
PrecompUtils,
System.SysUtils, System.Classes, System.Math;
var
Codec: TPrecompressor;
implementation
const
LZOCodecs: array of PChar = ['lzo1x'];
CODEC_COUNT = 1;
LZO1X_CODEC = 0;
const
L_WORKMEM = 524288;
L_MAXSIZE = 16 * 1024 * 1024;
LZO1X_999 = 0;
var
SOList: array of array [0 .. CODEC_COUNT - 1] of TSOList;
WrkMem: array of array [0 .. L_WORKMEM - 1] of Byte;
LZO1XVariant: Integer = LZO1X_999;
CodecAvailable, CodecEnabled: TArray<Boolean>;
type
PLZOSI = ^TLZOSI;
TLZOSI = record
CSize, DSize: Integer;
end;
var
LZOSB: array of Byte = [$11, $00, $00];
function GetLZOSI(InBuff: Pointer; InSize: Integer; OutBuff: Pointer;
OutSize: Integer; StreamInfo: PLZOSI): Boolean;
const
MinSize = 256;
RetryCount = -1;
var
I, Res: Integer;
OSize: NativeUInt;
Pos: NativeInt;
begin
Result := False;
if PWord(InBuff)^ = 0 then
exit;
StreamInfo^.CSize := Min(InSize, MinSize);
Res := -1;
I := 0;
while Res <> 0 do
begin
OSize := OutSize;
Res := lzo1x_decompress_safe(InBuff, Min(InSize, StreamInfo^.CSize),
OutBuff, @OSize);
case Res of
0:
begin
StreamInfo^.DSize := OSize;
if (StreamInfo^.CSize > MinSize) then
Result := True;
end;
-4, -7:
begin
if I = RetryCount then
break;
if BinarySearch(InBuff, StreamInfo^.CSize, InSize, @LZOSB[0],
Length(LZOSB), Pos) then
begin
Inc(I);
StreamInfo^.CSize := Pos + Length(LZOSB)
end
else
break;
end;
{ -5:
begin
// increase output buffer size and try again
break;
end; }
{ -8:
begin
// reduce input buffer size and try again
end; }
else
break;
end;
end;;
end;
function LZOInit(Command: PChar; Count: Integer; Funcs: PPrecompFuncs): Boolean;
var
I: Integer;
Options: TArray<Integer>;
S: String;
X, Y: Integer;
begin
Result := True;
SetLength(SOList, Count);
SetLength(WrkMem, 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] := LZODLL.DLLLoaded;
X := 0;
while Funcs^.GetCodec(Command, X, False) <> '' do
begin
S := Funcs^.GetCodec(Command, X, False);
if (CompareText(S, LZOCodecs[LZO1X_CODEC]) = 0) and LZODLL.DLLLoaded then
begin
CodecEnabled[LZO1X_CODEC] := True;
if Funcs^.GetParam(Command, X, 'v') = '999' then
LZO1XVariant := 0;
if Funcs^.GetParam(Command, X, 'l') <> '' then
for I := Low(SOList) to High(SOList) do
SOList[I][LZO1X_CODEC].Update
([StrToInt(Funcs^.GetParam(Command, X, 'l'))], True);
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 LZOFree(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 LZOParse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
var
S: String;
I: Integer;
begin
Result := False;
Option^ := 0;
I := 0;
while Funcs^.GetCodec(Command, I, False) <> '' do
begin
S := Funcs^.GetCodec(Command, I, False);
if (CompareText(S, LZOCodecs[LZO1X_CODEC]) = 0) and LZODLL.DLLLoaded then
begin
SetBits(Option^, 0, 0, 5);
SetBits(Option^, LZO1XVariant, 12, 5);
if Funcs^.GetParam(Command, I, 'l') <> '' then
SetBits(Option^, StrToInt(Funcs^.GetParam(Command, I, 'l')), 5, 7);
if Funcs^.GetParam(Command, I, 'v') = '999' then
SetBits(Option^, 0, 12, 5);
Result := True;
end;
Inc(I);
end;
end;
procedure LZOScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
var
Buffer: PByte;
Pos: NativeInt;
LZOSI: TLZOSI;
SI: _StrInfo1;
begin
if BoolArray(CodecEnabled, False) then
exit;
Buffer := Funcs^.Allocator(Instance, L_MAXSIZE);
Pos := 0;
while Pos < Size do
begin
if GetLZOSI(Input + Pos, SizeEx - Pos, Buffer, L_MAXSIZE, @LZOSI) then
begin
Output(Instance, Buffer, LZOSI.DSize);
SI.Position := Pos;
SI.OldSize := LZOSI.CSize;
SI.NewSize := LZOSI.DSize;
SI.Option := 0;
SI.Status := TStreamStatus.None;
Add(Instance, @SI, nil, nil);
Inc(Pos, LZOSI.CSize);
continue;
end;
Inc(Pos);
end;
end;
function LZOScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X: Integer;
Res: NativeUInt;
LZOSI: TLZOSI;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if (StreamInfo^.OldSize = 0) or (StreamInfo^.NewSize = 0) then
begin
Buffer := Funcs^.Allocator(Instance, L_MAXSIZE);
if GetLZOSI(Input, Size, Buffer, L_MAXSIZE, @LZOSI) then
begin
StreamInfo^.OldSize := LZOSI.CSize;
StreamInfo^.NewSize := LZOSI.DSize;
end;
end
else
Buffer := Funcs^.Allocator(Instance, StreamInfo^.NewSize);
Res := StreamInfo^.NewSize;
case X of
LZO1X_CODEC:
if not lzo1x_decompress_safe(Input, StreamInfo^.OldSize, Buffer, @Res) = 0
then
Res := 0;
end;
if Res = StreamInfo^.NewSize then
begin
StreamInfo^.NewSize := Res;
Output(Instance, Buffer, Res);
Result := True;
end;
end;
function LZOProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
I: Integer;
X: Integer;
Res1: NativeUInt;
Res2: NativeUInt;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
Buffer := Funcs^.Allocator(Instance, 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;
Res1 := StreamInfo^.NewSize;
case X of
LZO1X_CODEC:
case GetBits(StreamInfo^.Option, 12, 5) of
LZO1X_999:
if not lzo1x_999_compress_level(NewInput, StreamInfo^.NewSize,
Buffer, @Res1, @WrkMem[Instance, 0], nil, 0, nil, I) = 0 then
Res1 := 0;
{ if not lzo1x_1_compress(NewInput, StreamInfo^.NewSize, Buffer,
@Res1, @WrkMem[Instance, 0]) = 0 then
Res1 := 0; }
end;
end;
Result := (Res1 = StreamInfo^.OldSize) and CompareMem(OldInput, Buffer,
StreamInfo^.OldSize);
if Result then
begin
SetBits(StreamInfo^.Option, I, 5, 7);
SOList[Instance][X].Add(I);
break;
end;
case X of
LZO1X_CODEC:
if not GetBits(StreamInfo^.Option, 12, 5) in [0] then
break;
end;
end;
if (Result = False) and ((StreamInfo^.Status = TStreamStatus.Predicted) or
(SOList[Instance][X].Count = 1)) then
begin
Buffer := Funcs^.Allocator(Instance, Res1 + Max(StreamInfo^.OldSize, Res1));
Res2 := PrecompEncodePatch(OldInput, StreamInfo^.OldSize, Buffer, Res1,
Buffer + Res1, Max(StreamInfo^.OldSize, Res1));
if (Res2 > 0) and ((Res2 / Max(StreamInfo^.OldSize, Res1)) <= DIFF_TOLERANCE)
then
begin
Output(Instance, Buffer + Res1, Res2);
SetBits(StreamInfo^.Option, 1, 31, 1);
SOList[Instance][X].Add(I);
Result := True;
end;
end;
end;
function LZORestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X: Integer;
Res1: NativeUInt;
Res2: NativeUInt;
begin
Result := False;
X := GetBits(StreamInfo.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
Buffer := Funcs^.Allocator(Instance, StreamInfo.NewSize);
Res1 := StreamInfo.NewSize;
case X of
LZO1X_CODEC:
case GetBits(StreamInfo.Option, 12, 5) of
LZO1X_999:
if not lzo1x_999_compress_level(Input, StreamInfo.NewSize, Buffer,
@Res1, @WrkMem[Instance, 0], nil, 0, nil,
GetBits(StreamInfo.Option, 5, 7)) = 0 then
Res1 := 0;
end;
end;
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);
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(LZOCodecs) to High(LZOCodecs) do
begin
Codec.Names := Codec.Names + [LZOCodecs[I]];
StockMethods.Add(LZOCodecs[I]);
end;
Codec.Initialised := False;
Codec.Init := @LZOInit;
Codec.Free := @LZOFree;
Codec.Parse := @LZOParse;
Codec.Scan1 := @LZOScan1;
Codec.Scan2 := @LZOScan2;
Codec.Process := @LZOProcess;
Codec.Restore := @LZORestore;
SetLength(CodecAvailable, Length(Codec.Names));
SetLength(CodecEnabled, Length(Codec.Names));
end.

View File

@@ -0,0 +1,991 @@
unit PrecompMain;
interface
uses
Main, Threading, Utils, ParseClass, ParseExpr,
PrecompUtils, PrecompZLib,
WinAPI.Windows,
System.SysUtils, System.Classes, System.SyncObjs, System.Math, System.Types,
System.StrUtils, System.RTLConsts,
System.Generics.Defaults, System.Generics.Collections;
const
XTOOL_PRECOMP = $304C5458;
type
TEncodeOptions = record
Method: AnsiString;
ChunkSize, Threads: Integer;
Depth: Integer;
LowMem: Boolean;
HistorySize: Boolean;
HistoryFile: String;
end;
TDecodeOptions = record
Method: AnsiString;
Threads: Integer;
end;
procedure PrintHelp;
procedure Parse(ParamArg: TArray<string>; out Options: TEncodeOptions);
overload;
procedure Parse(ParamArg: TArray<string>; out Options: TDecodeOptions);
overload;
// reuse resources when going in-depth
// make an array of all common resources for depth
// depth will be hard af to add
// check if at least one of the functions exists in a dll before using it
// number of chunks to process when decoding
procedure Encode(Input, Output: TStream; Options: TEncodeOptions);
procedure Decode(Input, Output: TStream; Options: TDecodeOptions);
function PrecompGetCodec(Cmd: PAnsiChar; Index: Integer; WithParams: Boolean)
: PAnsiChar stdcall;
function PrecompGetParam(Cmd: PAnsiChar; Index: Integer; Param: PAnsiChar)
: PAnsiChar stdcall;
function PrecompAllocator(Instance: Integer; Size: Integer): Pointer stdcall;
procedure PrecompOutput1(Instance: Integer; const Buffer: Pointer;
Size: Integer)stdcall;
procedure PrecompOutput2(Instance: Integer; const Buffer: Pointer;
Size: Integer)stdcall;
procedure PrecompOutput3(Instance: Integer; const Buffer: Pointer;
Size: Integer)stdcall;
procedure PrecompAddStream1(Instance: Integer; Info: PStrInfo1;
Codec: PAnsiChar)stdcall;
implementation
var
Codecs: array of TPrecompressor;
PrecompFunctions: _PrecompFuncs;
procedure PrintHelp;
var
I, J: Integer;
S: string;
begin
Console.Write('precomp - data precompressor');
Console.Write('');
Console.Write('Usage:');
Console.Write
(' xtool precomp:method1,method2,methodN...:param1,param2,paramN... input output');
Console.Write('');
(* Console.Write('Methods:');
for I := Low(Codecs) to High(Codecs) do
begin
S := '';
for J := Low(Codecs[I]) to High(Codecs[I]) do
begin
if (IndexText(Codecs[I][J], Codecs[I]) = J) then
S := S + Codecs[I][J] + ', ';
end;
Delete(S, Length(S) - 1, 2);
Console.Write(' ' + S);
end; *)
Console.Write('');
Console.Write('Parameters:');
Console.Write(' c# - scanning range of precompressor [16mb]');
Console.Write(' t# - number of working threads [Threads/2]');
Console.Write(' lm - low memory mode');
Console.Write(' hs - enable history database');
Console.Write(' hf# - history database file');
Console.Write('');
end;
procedure Parse(ParamArg: TArray<string>; out Options: TEncodeOptions);
var
ArgParse: TArgParser;
ExpParse: TExpressionParser;
S: String;
begin
ArgParse := TArgParser.Create(ParamArg);
ExpParse := TExpressionParser.Create;
try
Options.Method := AnsiString(ArgParse.AsString('-m'));
S := ArgParse.AsString('-c', '16mb');
S := ReplaceText(S, 'KB', '* 1024^1');
S := ReplaceText(S, 'MB', '* 1024^2');
S := ReplaceText(S, 'GB', '* 1024^3');
Options.ChunkSize := Max(4194304, Round(ExpParse.Evaluate(S)));
S := ArgParse.AsString('-t', '50p');
S := ReplaceText(S, 'p', '%');
S := ReplaceText(S, '%', '%*' + CPUCount.ToString);
Options.Threads := Max(1, Round(ExpParse.Evaluate(S)));
Options.Depth := Succ(ArgParse.AsInteger('-d'));
Options.LowMem := ArgParse.AsBoolean('-lm');
finally
ArgParse.Free;
ExpParse.Free;
end;
end;
procedure Parse(ParamArg: TArray<string>; out Options: TDecodeOptions);
var
ArgParse: TArgParser;
ExpParse: TExpressionParser;
S: String;
begin
ArgParse := TArgParser.Create(ParamArg);
ExpParse := TExpressionParser.Create;
try
Options.Method := AnsiString(ArgParse.AsString('-m'));
S := ArgParse.AsString('-t', '50p');
S := ReplaceText(S, 'p', '%');
S := ReplaceText(S, '%', '%*' + CPUCount.ToString);
Options.Threads := Max(1, Round(ExpParse.Evaluate(S)));
finally
ArgParse.Free;
ExpParse.Free;
end;
end;
function GetIndex(Scanned, Processed: TArray<Boolean>): Integer;
var
I: Integer;
begin
if BoolArray(Processed, True) then
begin
Result := -2;
exit;
end
else
Result := -1;
for I := Low(Scanned) to High(Scanned) do
begin
if (Scanned[I] = True) and (Processed[I] = False) then
begin
Result := I;
break;
end;
end;
end;
type
TCommonVars = record
MemStream: TMemoryStream;
DataStore: TDataStore;
MemOutput: TArray<TMemoryStream>;
InfoStore1: TArray<TListEx<TEncodeSI>>;
InfoStore2: TList<TFutureSI>;
Scanned1, Scanned2, Processed: TArray<Boolean>;
CurPos: TArray<Int64>;
CurCodec: TArray<Byte>;
StrIdx: TArray<Integer>;
ThrIdx: TArray<Integer>;
end;
var
ComVars: TArray<TCommonVars>;
DepIdx: TArray<Integer>;
Sync: TCriticalSection;
Tasks: TArray<TTask>;
WorkStream: TArray<TMemoryStream>;
History: TDictionary<Int64, THistory>;
Duplicates: TDictionary<Int64, TDuplicate>;
// history should not depend on the streams about to be processed, check before doing this
procedure CodecInit(Count: Integer; Method: AnsiString);
var
I, X, Y: Integer;
S: AnsiString;
List: TStringDynArray;
begin
PrecompFunctions.GetCodec := @PrecompGetCodec;
PrecompFunctions.GetParam := @PrecompGetParam;
PrecompFunctions.Allocator := @PrecompAllocator;
if Method = '' then
exit;
Insert(PrecompZLib.Codec, Codecs, Length(Codecs));
for X := High(Codecs) downto Low(Codecs) do
for Y := Low(Codecs[X].Names) to High(Codecs[X].Names) do
Insert(String(Codecs[X].Names[Y]), List, Length(List));
I := 0;
while Assigned(PrecompGetCodec(PAnsiChar(Method), I, False)) do
begin
if IndexText(String(PrecompGetCodec(PAnsiChar(Method), I, False)), List) < 0
then
raise Exception.CreateFmt(SPrecompError1,
[String(PrecompGetCodec(PAnsiChar(Method), I, False))]);
Inc(I);
end;
for X := High(Codecs) downto Low(Codecs) do
begin
S := '';
for Y := Low(Codecs[X].Names) to High(Codecs[X].Names) do
begin
I := 0;
while Assigned(PrecompGetCodec(PAnsiChar(Method), I, False)) do
begin
if SameText(String(PrecompGetCodec(PAnsiChar(Method), I, False)),
String(Codecs[X].Names[Y])) then
S := S + AnsiString(PrecompGetCodec(PAnsiChar(Method), I,
True)) + '+';
Inc(I);
end;
end;
if S <> '' then
begin
SetLength(S, Length(S) - 1);
Codecs[X].Initialized := Codecs[X].Init(PAnsiChar(S), Count,
@PrecompFunctions);
end
else
Delete(Codecs, X, 1);
end;
end;
procedure CodecFree(Count: Integer);
var
I: Integer;
begin
for I := Low(Codecs) to High(Codecs) do
if Codecs[I].Initialized then
Codecs[I].Free(@PrecompFunctions);
end;
function PrecompGetCodec(Cmd: PAnsiChar; Index: Integer; WithParams: Boolean)
: PAnsiChar;
var
List: TStringDynArray;
begin
Result := nil;
if Assigned(Cmd) then
begin
List := DecodeStr(String(Cmd), '+');
if InRange(Index, Low(List), High(List)) then
if WithParams then
Result := PAnsiChar(AnsiString(List[Index]))
else
Result := PAnsiChar(AnsiString(DecodeStr(List[Index], ':')[0]));
end;
end;
function PrecompGetParam(Cmd: PAnsiChar; Index: Integer; Param: PAnsiChar)
: PAnsiChar;
var
List1, List2: TStringDynArray;
I: Integer;
begin
Result := nil;
if Assigned(Cmd) then
begin
List1 := DecodeStr(String(Cmd), '+');
if InRange(Index, Low(List1), High(List1)) then
begin
List2 := DecodeStr(List1[Index], ':');
if Length(List2) > 1 then
begin
if not Assigned(Param) then
Result := PAnsiChar(AnsiString(List2[1]))
else
begin
List1 := DecodeStr(List2[1], ',');
for I := Low(List1) to High(List1) do
if List1[I].StartsWith(String(Param), True) then
Result := PAnsiChar
(AnsiString(List1[I].Substring(Length(String(Param)))));
end;
end;
end;
end;
end;
function PrecompAllocator(Instance: Integer; Size: Integer): Pointer;
begin
with ComVars[DepIdx[Instance]] do
begin
if WorkStream[Instance].Size < Size then
WorkStream[Instance].Size := Size;
Result := WorkStream[Instance].Memory;
end;
end;
procedure PrecompOutput1(Instance: Integer; const Buffer: Pointer;
Size: Integer);
begin
with ComVars[DepIdx[Instance]] do
begin
case Size of
- 1:
MemOutput[Instance].Position := CurPos[Instance];
else
MemOutput[Instance].WriteBuffer(Buffer^, Size);
end;
end;
end;
// TMemoryMap
procedure PrecompAddStream1(Instance: Integer; Info: PStrInfo1;
Codec: PAnsiChar);
var
SI1: TEncodeSI;
SI2: TFutureSI;
LValid: Boolean;
LCodec: Byte;
LOption: Integer;
I, X, Y: Integer;
S: String;
begin
// add overhead function
with ComVars[DepIdx[Instance]] do
begin
if (Info^.Position < 0) or (MemOutput[Instance].Position - CurPos[Instance]
<> Info^.NewSize) then
begin
MemOutput[Instance].Position := CurPos[Instance];
exit;
end;
if Assigned(Codec) then
begin
LValid := False;
I := 0;
while Assigned(PrecompGetCodec(Codec, I, False)) do
begin
for X := Low(Codecs) to High(Codecs) do
begin
for Y := Low(Codecs[X].Names) to High(Codecs[X].Names) do
if SameText(String(PrecompGetCodec(Codec, I, False)),
String(Codecs[X].Names[Y])) then
begin
LCodec := X;
if Codecs[X].Initialized then
if Codecs[X].Parse(PrecompGetCodec(Codec, I, True), @LOption,
@PrecompFunctions) then
begin
LValid := True;
break;
end;
end;
if LValid then
break;
end;
Inc(I);
end;
if not LValid then
begin
MemOutput[Instance].Position := CurPos[Instance];
exit;
end;
end
else
begin
LCodec := CurCodec[Instance];
LOption := Info^.Option;
end;
if Info^.Position < Min(DataStore.Size, DataStore.Slot[Instance].Size) then
begin
FillChar(SI1, SizeOf(TEncodeSI), 0);
SI1.ActualPosition := Info^.Position;
SI1.StorePosition := CurPos[Instance];
SI1.OriginalSize := Info^.OldSize;
SI1.UnpackedSize := Info^.NewSize;
SI1.Codec := LCodec;
SI1.Option := LOption;
SI1.Status := Info^.Status;
InfoStore1[Instance].Add(SI1);
end
else
begin
FillChar(SI2, SizeOf(TFutureSI), 0);
SI2.Position := DataStore.Position[Instance] + Info^.Position;
SI2.OriginalSize := Info^.OldSize;
SI2.UnpackedSize := Info^.NewSize;
SI2.Codec := LCodec;
SI2.Option := LOption;
SI2.Status := Info^.Status;
Sync.Acquire;
InfoStore2.Add(SI2);
Sync.Release;
end;
CurPos[Instance] := MemOutput[Instance].Position;
end;
end;
// endian(CSize,4)
procedure Scan1(Index: Integer);
var
I: Integer;
begin
with ComVars[DepIdx[Index]] do
for I := Low(Codecs) to High(Codecs) do
begin
try
CurPos[Index] := MemOutput[Index].Position;
CurCodec[Index] := I;
Codecs[I].Scan1(Index, DataStore.Slot[Index].Memory,
Min(DataStore.Size, DataStore.Slot[Index].Size),
DataStore.Slot[Index].Size, @PrecompOutput1, @PrecompAddStream1,
@PrecompFunctions);
except
end;
end;
end;
procedure Scan2(Index: Integer);
var
I: Integer;
begin
(* while StrIdx2[Index] < InfoStore2.Count do
begin
// if InfoStore2[StrIdx2[Index]].Position then
// there is a problem here with the count when multi threading...
Inc(StrIdx2[Index]);
end;
for I := Low(Codecs) to High(Codecs) do
begin
try
CurPos[Index] := MemOutput[Index].Position;
CurCodec[Index] := I;
Codecs[Index][I].Scan2(Index, DataStore.Slot[Index].Memory,
Min(DataStore.Size, DataStore.Slot[Index].Size),
DataStore.Slot[Index].Size, @PrecompAllocator, @PrecompCompress,
@PrecompOutput1, @PrecompAddStream1);
except
end;
end; *)
end;
// use TDictionary for history and deduplication
procedure Process(Index, ThreadIndex, StreamIndex: Integer);
var
SI1: _StrInfo2;
SI2: TEncodeSI;
Res: Boolean;
begin
with ComVars[DepIdx[Index]] do
begin
SI2 := InfoStore1[ThreadIndex][StreamIndex];
SI1.OldSize := SI2.OriginalSize;
SI1.NewSize := SI2.UnpackedSize;
SI1.Option := SI2.Option;
SI1.Status := SI2.Status;
CurPos[Index] := MemOutput[Index].Position;
CurCodec[Index] := SI2.Codec;
try
Res := Codecs[SI2.Codec].Process(Index,
PByte(DataStore.Slot[ThreadIndex].Memory) + SI2.ActualPosition,
PByte(MemOutput[ThreadIndex].Memory) + SI2.StorePosition, @SI1,
@PrecompOutput1, @PrecompFunctions);
except
Res := False;
end;
if Res then
begin
SI2.OriginalSize := SI1.OldSize;
SI2.UnpackedSize := SI1.NewSize;
SI2.Option := SI1.Option;
SI2.Status := TStreamStatus(SuccessStatus);
SI2.ExtPosition := CurPos[Index];
SI2.ExtSize := MemOutput[Index].Position - CurPos[Index];
SI2.ExtThread := Index;
InfoStore1[ThreadIndex][StreamIndex] := SI2;
CurPos[Index] := MemOutput[Index].Position;
end;
end;
end;
procedure EncThread(Y: Integer);
var
X, Z: Integer;
History: Boolean;
begin
with ComVars[DepIdx[Y]] do
begin
if InRange(Y, Low(InfoStore1), High(InfoStore1)) then
begin
Scan1(Y);
Scanned1[Y] := True;
// try to process even before scan finishes
(* if ExternalInUse(EOptions.Method) then
while BoolArray(Scanned1, False) do
Sleep(10); *)
// Scan2(Y);
InfoStore1[Y].Sort;
Scanned2[Y] := True;
end;
// if index < count give the thread index, check this for all threads
// should give more speed
while True do
begin
Z := GetIndex(Scanned2, Processed);
while Z = -1 do
begin
Sleep(10);
Z := GetIndex(Scanned2, Processed);
end;
ThrIdx[Y] := Z;
if Z < -1 then
break;
X := AtomicIncrement(StrIdx[Z]);
while X < InfoStore1[Z].Count do
begin
History := False;
Process(Y, Z, X);
if History = False then
begin
// Int64Rec(HD.Tag).Lo := SI.Checksum;
// Int64Rec(HD.Tag).Hi := SI.UnpackedSize;
end;
Z := GetIndex(Scanned2, Processed);
while Z = -1 do
begin
Sleep(10);
Z := GetIndex(Scanned2, Processed);
end;
ThrIdx[Y] := Z;
if Z < -1 then
break;
X := AtomicIncrement(StrIdx[Z]);
end;
if Z < -1 then
break;
if X >= InfoStore1[Z].Count then
Processed[Z] := True;
end;
end;
end;
procedure InternalEncode(Input, Output: TStream; Options: TEncodeOptions;
Index, Depth: Integer);
var
GUID: TGUID;
StreamInfo: TEncodeSI;
StreamHeader: TStreamHeader;
StreamCount: Int32;
BlockSize: Int64;
UI32: UInt32;
I, J: Integer;
LastStream, LastPos: Int64;
begin
I := XTOOL_PRECOMP;
Output.WriteBuffer(I, I.Size);
CreateGUID(GUID);
Output.WriteBuffer(GUID, SizeOf(GUID));
LongRec(I).Bytes[0] := Length(Options.Method);
Output.WriteBuffer(LongRec(I).Bytes[0], LongRec(I).Bytes[0].Size);
Output.WriteBuffer(Options.Method[1], LongRec(I).Bytes[0]);
Sync := TCriticalSection.Create;
if Index = 0 then
begin
SetLength(DepIdx, Options.Threads);
SetLength(ComVars, Options.Depth);
for J := Low(ComVars) to High(ComVars) do
with ComVars[J] do
begin
MemStream := TMemoryStream.Create;
SetLength(MemOutput, Options.Threads);
SetLength(ThrIdx, Options.Threads);
if Options.LowMem then
I := 1
else
I := Options.Threads;
SetLength(InfoStore1, I);
SetLength(StrIdx, I);
SetLength(Scanned1, I);
SetLength(Scanned2, I);
SetLength(Processed, I);
SetLength(CurPos, I);
SetLength(CurCodec, I);
end;
end;
SetLength(Tasks, Options.Threads);
SetLength(WorkStream, Options.Threads);
for I := Low(Tasks) to High(Tasks) do
begin
if Length(Tasks) > 1 then
Tasks[I] := TTask.Create(I);
MemOutput[I] := TMemoryStream.Create;
WorkStream[I] := TMemoryStream.Create;
end;
for I := Low(InfoStore1) to High(InfoStore1) do
InfoStore1[I] := TListEx<TEncodeSI>.Create(EncodeSICmp);
InfoStore2 := TList<TFutureSI>.Create(FutureSICmp);
// if FileExists(Options.HistoryFile) then
// LoadHistory(HistoryList, Options.HistoryFile);
DataStore := TDataStore.Create(Input, True, Length(InfoStore1),
Options.ChunkSize);
CodecInit(Options.Threads, Options.Method);
LastStream := 0;
DataStore.Load;
while not DataStore.Done do
begin
if Length(Tasks) > 1 then
if IsErrored(Tasks) then
for I := Low(Tasks) to High(Tasks) do
Tasks[I].RaiseLastError;
for I := Low(InfoStore1) to High(InfoStore1) do
begin
InfoStore1[I].Count := 0;
StrIdx[I] := -1;
Scanned1[I] := False;
Scanned2[I] := False;
Processed[I] := False;
CurPos[I] := 0;
end;
for I := Low(Tasks) to High(Tasks) do
begin
ThrIdx[I] := 0;
MemOutput[I].Position := 0;
if Length(Tasks) > 1 then
begin
Tasks[I].Perform(EncThread);
Tasks[I].Start;
end
else
EncThread(0);
end;
for I := Low(InfoStore1) to High(InfoStore1) do
begin
while Processed[I] = False do
Sleep(10);
for J := Low(ThrIdx) to High(ThrIdx) do
while ThrIdx[J] = I do
Sleep(10);
// DEC MEM LIMIT HERE
LastPos := LastStream;
MemStream.Position := 0;
StreamCount := 0;
BlockSize := 0;
MemStream.WriteBuffer(StreamCount, StreamCount.Size);
MemStream.WriteBuffer(BlockSize, BlockSize.Size);
if InfoStore1[I].Count > 0 then
begin
InfoStore1[I].Index := 0;
J := InfoStore1[I].Get(StreamInfo);
while J >= 0 do
begin
if (Integer(StreamInfo.Status) <> SuccessStatus) or
(LastStream > StreamInfo.ActualPosition) or
(StreamInfo.ActualPosition >= Options.ChunkSize) then
InfoStore1[I].Delete(J)
else
begin
Inc(StreamCount);
StreamHeader.Kind := DEFAULT_STREAM;
if StreamInfo.ExtSize > 0 then
StreamHeader.Kind := StreamHeader.Kind or EXTENDED_STREAM;
StreamHeader.OldSize := StreamInfo.OriginalSize;
StreamHeader.NewSize := StreamInfo.UnpackedSize;
if StreamInfo.ExtSize > 0 then
begin
Inc(StreamHeader.NewSize, StreamInfo.ExtSize);
Inc(StreamHeader.NewSize, StreamInfo.ExtSize.Size);
end;
StreamHeader.Codec := StreamInfo.Codec;
StreamHeader.Option := StreamInfo.Option;
Inc(BlockSize, StreamHeader.NewSize);
MemStream.WriteBuffer(StreamHeader, SizeOf(TStreamHeader));
LastStream := Int64(StreamInfo.ActualPosition) +
StreamInfo.OriginalSize;
end;
J := InfoStore1[I].Get(StreamInfo);
end;
MemStream.Position := 0;
MemStream.WriteBuffer(StreamCount, StreamCount.Size);
MemStream.WriteBuffer(BlockSize, BlockSize.Size);
Output.WriteBuffer(MemStream.Memory^, MemStream.Position + StreamCount *
SizeOf(TStreamHeader));
InfoStore1[I].Index := 0;
J := InfoStore1[I].Get(StreamInfo);
while J >= 0 do
begin
Output.WriteBuffer
((PByte(MemOutput[I].Memory) + StreamInfo.StorePosition)^,
StreamInfo.UnpackedSize);
if StreamInfo.ExtSize > 0 then
begin
Output.WriteBuffer((PByte(MemOutput[StreamInfo.ExtThread].Memory) +
StreamInfo.ExtPosition)^, StreamInfo.ExtSize);
Output.WriteBuffer(StreamInfo.ExtSize, StreamInfo.ExtSize.Size);
end;
J := InfoStore1[I].Get(StreamInfo);
end;
InfoStore1[I].Index := 0;
J := InfoStore1[I].Get(StreamInfo);
while J >= 0 do
begin
UI32 := StreamInfo.ActualPosition - LastPos;
Output.WriteBuffer(UI32, UI32.Size);
if UI32 > 0 then
Output.WriteBuffer((PByte(DataStore.Slot[I].Memory) +
LastPos)^, UI32);
LastPos := StreamInfo.ActualPosition + StreamInfo.OriginalSize;
J := InfoStore1[I].Get(StreamInfo);
end;
end
else
Output.WriteBuffer(StreamCount, StreamCount.Size);
UI32 := Max(Min(Options.ChunkSize, DataStore.Slot[I].Size) - LastPos, 0);
Output.WriteBuffer(UI32, UI32.Size);
if UI32 > 0 then
Output.WriteBuffer((PByte(DataStore.Slot[I].Memory) + LastPos)^, UI32);
LastStream := Max(LastStream - Options.ChunkSize, 0);
if I > 0 then
DataStore.LoadEx;
end;
DataStore.LoadEx;
if Length(Tasks) > 1 then
WaitForAll(Tasks);
end;
StreamCount := StreamCount.MinValue;
Output.WriteBuffer(StreamCount, StreamCount.Size);
CodecFree(Options.Threads);
for I := Low(Tasks) to High(Tasks) do
begin
if Length(Tasks) > 1 then
Tasks[I].Free;
MemOutput[I].Free;
WorkStream[I].Free;
end;
for I := Low(InfoStore1) to High(InfoStore1) do
InfoStore1[I].Free;
InfoStore2.Free;
DataStore.Free;
// if Options.HistoryFile <> '' then
// SaveHistory(HistoryList, Options.HistoryFile);
// SetLength(HistoryList, 0);
MemStream.Free;
Sync.Free;
end;
var
DecInput, DecOutput: TStream;
Idx: Integer;
StreamPos: TArray<Int64>;
Completed: TArray<Boolean>;
StreamCount: Int32;
BlockPos: Int64;
MemInput: TMemoryStream;
procedure PrecompOutput2(Instance: Integer; const Buffer: Pointer;
Size: Integer);
begin
DecOutput.WriteBuffer(Buffer^, Size);
end;
procedure PrecompOutput3(Instance: Integer; const Buffer: Pointer;
Size: Integer);
begin
MemOutput[Instance].WriteBuffer(Buffer^, Size);
end;
procedure Restore(MT: Boolean; ThreadIndex: Integer);
var
X: Integer;
Pos: Int64;
X64: Int64;
SI: _StrInfo3;
SH: PStreamHeader;
UI32: UInt32;
Ptr1, Ptr2: PByte;
LOutput: _PrecompOutput;
begin
Pos := 0;
X := AtomicIncrement(Idx);
while X < StreamCount do
begin
SH := PStreamHeader((PByte(MemStream.Memory) + X * SizeOf(TStreamHeader)));
if MT then
begin
LOutput := @PrecompOutput3;
Pos := StreamPos[X];
X64 := Pos + SH^.NewSize;
while (BlockPos < X64) do
begin
if IsErrored(Tasks) or (BlockPos < 0) then
exit;
Sleep(1);
end;
MemOutput[ThreadIndex].Position := 0;
end
else
begin
LOutput := @PrecompOutput2;
DecInput.ReadBuffer(UI32, UI32.Size);
if UI32 > 0 then
DecOutput.CopyFrom(DecInput, UI32);
end;
SI.OldSize := SH^.OldSize;
SI.NewSize := SH^.NewSize;
SI.Option := SH^.Option;
Ptr1 := PByte(MemInput.Memory) + Pos;
if SH^.Kind and EXTENDED_STREAM = EXTENDED_STREAM then
begin
SI.ExtSize := PInteger(Ptr1 + SI.NewSize - SI.NewSize.Size)^;
SI.NewSize := SI.NewSize - SI.ExtSize - SI.ExtSize.Size;
Ptr2 := PByte(MemInput.Memory) + Pos + SI.NewSize;
end
else
Ptr2 := nil;
if (Codecs[SH^.Codec].Restore(ThreadIndex, Ptr1, Ptr2, SI, LOutput,
@PrecompFunctions) = False) then
raise Exception.CreateFmt(SPrecompError3,
[String(Codecs[SH^.Codec].Names[0])]);
if MT then
begin
Move(MemOutput[ThreadIndex].Memory^, Ptr1^, SI.OldSize);
Completed[X] := True;
end
else
begin
Inc(Pos, SH^.NewSize);
end;
X := AtomicIncrement(Idx);;
end;
end;
procedure DecThread(Y: Integer);
begin
Restore(True, Y);
end;
procedure ReadCallback(Pos: Int64);
begin
BlockPos := Pos;
end;
// restore stuff by chunk
procedure InternalDecode(Input, Output: TStream; Options: TDecodeOptions;
Index, Depth: Integer);
var
GUID: TGUID;
StreamHeader: PStreamHeader;
BlockSize: Int64;
CurrPos: Int64;
UI32: UInt32;
I, J: Integer;
begin
DecInput := Input;
DecOutput := Output;
Input.ReadBuffer(GUID, SizeOf(GUID));
Input.ReadBuffer(LongRec(I).Bytes[0], LongRec(I).Bytes[0].Size);
SetLength(Options.Method, LongRec(I).Bytes[0]);
Input.ReadBuffer(Options.Method[1], LongRec(I).Bytes[0]);
MemStream := TMemoryStream.Create;
SetLength(Tasks, Options.Threads);
SetLength(MemOutput, Options.Threads);
SetLength(WorkStream, Options.Threads);
for I := Low(Tasks) to High(Tasks) do
begin
if Length(Tasks) > 1 then
Tasks[I] := TTask.Create(I);
MemOutput[I] := TMemoryStream.Create;
WorkStream[I] := TMemoryStream.Create;
end;
MemInput := TMemoryStream.Create;
CodecInit(Options.Threads, Options.Method);
Input.ReadBuffer(StreamCount, StreamCount.Size);
while StreamCount >= 0 do
begin
if Length(Tasks) > 1 then
if IsErrored(Tasks) then
for I := Low(Tasks) to High(Tasks) do
Tasks[I].RaiseLastError;
if StreamCount > 0 then
begin
BlockPos := 0;
Input.ReadBuffer(BlockSize, BlockSize.Size);
MemStream.Position := 0;
MemStream.CopyFrom(Input, StreamCount * SizeOf(TStreamHeader));
CurrPos := 0;
if (Options.Threads > 1) and (StreamCount > 1) then
begin
if StreamCount > Length(StreamPos) then
SetLength(StreamPos, StreamCount);
SetLength(Completed, Length(StreamPos));
for J := 0 to StreamCount - 1 do
begin
StreamPos[J] := CurrPos;
Completed[J] := False;
StreamHeader :=
PStreamHeader((PByte(MemStream.Memory) + J *
SizeOf(TStreamHeader)));
Inc(CurrPos, Max(StreamHeader^.OldSize, StreamHeader^.NewSize));
end;
end;
if MemInput.Size < BlockSize then
MemInput.Size := BlockSize;
MemInput.Position := 0;
Idx := -1;
if (Options.Threads > 1) and (StreamCount > 1) then
begin
for I := Low(Tasks) to High(Tasks) do
begin
Tasks[I].Perform(DecThread);
Tasks[I].Start;
end;
for J := 0 to StreamCount - 1 do
begin
StreamHeader :=
PStreamHeader((PByte(MemStream.Memory) + J *
SizeOf(TStreamHeader)));
MemInput.Size := Max(MemInput.Size, MemInput.Position +
Max(StreamHeader^.OldSize, StreamHeader^.NewSize));
if CopyStream(Input, MemInput, StreamHeader^.NewSize) <>
StreamHeader^.NewSize then
begin
BlockPos := -1;
raise EReadError.CreateRes(@SReadError);
end;
Inc(BlockPos, Max(StreamHeader^.OldSize, StreamHeader^.NewSize));
end;
end
else
MemInput.CopyFrom(Input, BlockSize);
if (Options.Threads > 1) and (StreamCount > 1) then
begin
for J := 0 to StreamCount - 1 do
begin
Input.ReadBuffer(UI32, UI32.Size);
if UI32 > 0 then
Output.CopyFrom(Input, UI32);
while (Completed[J] = False) and (IsErrored(Tasks) = False) do
Sleep(1);
if IsErrored(Tasks) then
for I := Low(Tasks) to High(Tasks) do
Tasks[I].RaiseLastError;
Output.WriteBuffer((PByte(MemInput.Memory) + StreamPos[J])^,
PStreamHeader((PByte(MemStream.Memory) + J * SizeOf(TStreamHeader)))
^.OldSize);
end;
WaitForAll(Tasks);
end
else
Restore(False, 0);
end;
Input.ReadBuffer(UI32, UI32.Size);
if UI32 > 0 then
Output.CopyFrom(Input, UI32);
Input.ReadBuffer(StreamCount, StreamCount.Size);
end;
CodecFree(Options.Threads);
MemInput.Free;
for I := Low(Tasks) to High(Tasks) do
begin
if Length(Tasks) > 1 then
Tasks[I].Free;
MemOutput[I].Free;
WorkStream[I].Free;
end;
MemStream.Free;
end;
procedure Encode(Input, Output: TStream; Options: TEncodeOptions);
begin
InternalEncode(Input, Output, Options, 0, 0);
end;
procedure Decode(Input, Output: TStream; Options: TDecodeOptions);
begin
InternalDecode(Input, Output, Options, 0, 0);
end;
end.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,616 @@
unit PrecompOodle;
interface
uses
OodleDLL, XDeltaDLL,
Utils,
PrecompUtils,
System.SysUtils, 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_TRADEOFF = 256;
var
SOList: array of array [0 .. CODEC_COUNT - 1] of TSOList;
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 + 2 <= Size then
begin
if (PWord(Buff + BlkSize + 2)^ = (((Buff + 1)^ shl 8) + $4C)) or
((First = True) and ((Buff + BlkSize + 2)^ in [$0C, $4C])) then
begin
Inc(StreamInfo^.CSize, BlkSize + 2);
Inc(StreamInfo^.DSize, BlkSize);
end;
end
else
I := BlkSize + 2 - Size;
if StreamInfo^.CSize + I > Size then
begin
StreamInfo^.CSize := 0;
StreamInfo^.DSize := 0;
exit;
end;
Inc(StreamInfo^.CSize, Abs(I));
Inc(StreamInfo^.DSize, Abs(I) - 2);
Dec(MaxBlocks);
if I > 0 then
GetOodleSI(Buff + I, 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
end; }
function CustomLZ_Decompress(src, dst: PByte; srcSize, dstCapacity: Integer;
Ident: Byte; var Res: Integer): Boolean;
const
BlkSize = 262144;
UpLen = 256;
DownLen = 16;
var
A, B, I, J, X: Integer;
Sizes: array [0 .. UpLen + DownLen - 1] of Integer;
begin
B := IfThen(dstCapacity mod BlkSize = 0, Pred(dstCapacity div BlkSize),
dstCapacity div BlkSize) * BlkSize;
FillChar((dst + B)^, dstCapacity - B, Ident);
OodleLZ_Decompress(src, srcSize, dst, dstCapacity);
A := Pred(dstCapacity);
while A > B do
begin
if (dst + A)^ <> Ident then
break;
Dec(A);
end;
Inc(A);
for I := Low(Sizes) to High(Sizes) do
Sizes[I] := -1;
J := Min(dstCapacity, A + UpLen);
I := Max(B, A - DownLen);
X := J - I;
while (J > I) do
begin
FillChar((dst + I)^, X, Ident);
OodleLZ_Decompress(src, srcSize, dst, J);
A := Pred(J);
while A > B do
begin
if (dst + A)^ <> Ident then
break;
Dec(A);
end;
Inc(A);
Sizes[Length(Sizes) - (J - I)] := A;
Dec(J);
end;
for I := Low(Sizes) to High(Sizes) do
begin
A := Sizes[I];
for J := Low(Sizes) to High(Sizes) do
begin
B := Sizes[J];
if I <> J then
if A = B 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
Res := Sizes[I];
Result := True;
break;
end;
end;
function GetOodleUS(Instance: Integer; Input: PByte; Pos: NativeInt;
StreamInfo: POodleSI; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs): Integer;
const
MinSize = 64;
var
Buffer: PByte;
Res: Integer;
SI: _StrInfo1;
begin
Result := 0;
if StreamInfo^.Codec = 3 then
exit;
Buffer := Funcs^.Allocator(Instance, StreamInfo^.DSize);
if CustomLZ_Decompress(Input + Pos, Buffer, StreamInfo^.CSize,
StreamInfo^.DSize, $32, Res) then
begin
if (Res > MinSize) and (Res > StreamInfo^.CSize) then
begin
Output(Instance, Buffer, Res);
SI.Position := Pos;
SI.OldSize := StreamInfo^.CSize;
SI.NewSize := Res;
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;
Add(Instance, @SI, nil, nil);
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, '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
Pos: NativeInt;
OodleSI: TOodleSI;
begin
if BoolArray(CodecEnabled, False) then
exit;
Pos := 0;
while Pos < Size do
begin
GetOodleSI(Input + Pos, SizeEx - Pos, @OodleSI);
if (OodleSI.CSize > 0) then
if GetOodleUS(Instance, Input, Pos, @OodleSI, Output, Add, Funcs) > 0 then
begin
Inc(Pos, OodleSI.CSize);
continue;
end;
Inc(Pos);
end;
end;
function OodleScan2(Instance, Depth: Integer; Input: Pointer; Size: cardinal;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
Res: Integer;
OodleSI: TOodleSI;
begin
Result := False;
if StreamInfo^.NewSize <= 0 then
exit;
Buffer := Funcs^.Allocator(Instance, StreamInfo^.NewSize);
if StreamInfo^.OldSize <= Size then
begin
if GetBits(StreamInfo^.Option, 0, 5) = LZNA_CODEC then
OodleSI.CSize := StreamInfo^.OldSize
else
GetOodleSI(Input, Size, @OodleSI);
if (OodleSI.CSize > 0) then
begin
Res := OodleLZ_Decompress(Input, OodleSI.CSize, Buffer,
StreamInfo^.NewSize);
if Res = StreamInfo^.NewSize then
begin
StreamInfo^.OldSize := OodleSI.CSize;
Output(Instance, Buffer, Res);
Result := True;
end;
end;
end;
end;
function OodleProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
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);
Res1 := OodleLZ_Compress(Y, NewInput, StreamInfo^.NewSize, Buffer, I,
@COptions);
Result := (Res1 = StreamInfo^.OldSize) and CompareMem(OldInput, Buffer,
StreamInfo^.OldSize);
if Result then
begin
SetBits(StreamInfo^.Option, I, 5, 7);
SOList[Instance][X].Add(I);
break;
end;
end;
if (Result = False) and ((StreamInfo^.Status = TStreamStatus.Predicted) or
(SOList[Instance][X].Count = 1)) then
begin
Buffer := Funcs^.Allocator(Instance, Res1 + Max(StreamInfo^.OldSize, Res1));
Res2 := PrecompEncodePatch(OldInput, StreamInfo^.OldSize, Buffer, Res1,
Buffer + Res1, Max(StreamInfo^.OldSize, Res1));
if (Res2 > 0) and ((Res2 / Max(StreamInfo^.OldSize, Res1)) <= DIFF_TOLERANCE)
then
begin
Output(Instance, Buffer + Res1, Res2);
SetBits(StreamInfo^.Option, 1, 31, 1);
SOList[Instance][X].Add(I);
Result := True;
end;
end;
end;
function OodleRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
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);
Res1 := OodleLZ_Compress(Y, Input, StreamInfo.NewSize, Buffer,
GetBits(StreamInfo.Option, 5, 7), @COptions);
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);
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.

View File

@@ -0,0 +1,268 @@
unit PrecompSearch;
interface
uses
Utils, SynCommons, SynCrypto,
PrecompUtils,
WinAPI.Windows,
System.SysUtils, System.Classes, System.StrUtils,
System.Types, System.Math, System.IOUtils;
const
XTOOL_DB = $42445458;
var
Codec: TPrecompressor;
implementation
type
PEntryStruct = ^TEntryStruct;
TEntryStruct = record
Position: Int64;
OldSize, NewSize: Integer;
end;
PSearchStruct = ^TSearchStruct;
TSearchStruct = record
Name: String;
SearchInt: Int64;
HashSize: Integer;
HashDigest: TMD5Digest;
Codec: String;
Resource: Integer;
EntryList: TArray<TEntryStruct>;
end;
var
SearchList: TStringDynArray;
SearchInfo: TArray<TArray<TArray<Integer>>>;
SearchCount: TArray<TArray<Integer>>;
CodecSearch: TArray<TArray<TSearchStruct>>;
CodecAvailable, CodecEnabled: TArray<Boolean>;
function SearchInit(Command: PChar; Count: Integer;
Funcs: PPrecompFuncs): Boolean;
var
I: Integer;
X, Y, Z: Integer;
S: String;
begin
Result := True;
for X := Low(CodecAvailable) to High(CodecAvailable) do
begin
CodecAvailable[X] := True;
CodecEnabled[X] := False;
end;
for X := Low(CodecSearch) to High(CodecSearch) do
for Y := Low(CodecSearch[X]) to High(CodecSearch[X]) do
CodecSearch[X, Y].Resource := RegisterResources(CodecSearch[X, Y].Codec);
X := 0;
while Funcs^.GetCodec(Command, X, False) <> '' do
begin
S := Funcs^.GetCodec(Command, X, False);
for Y := Low(Codec.Names) to High(Codec.Names) do
if CompareText(S, Codec.Names[Y]) = 0 then
begin
CodecEnabled[Y] := True;
break;
end;
Inc(X);
end;
I := 0;
for X := Low(CodecEnabled) to High(CodecEnabled) do
if CodecEnabled[X] then
begin
SetLength(SearchInfo[X], $10000);
SetLength(SearchCount[X], $10000);
for Z := Low(SearchInfo[X]) to High(SearchInfo[X]) do
begin
SearchCount[X, Z] := 0;
for Y := Low(CodecSearch[X]) to High(CodecSearch[X]) do
begin
LongRec(I).Words[0] := Int64Rec(CodecSearch[X, Y].SearchInt).Words[0];
if Z = I then
begin
Inc(SearchCount[X, Z]);
Insert(Y, SearchInfo[X, Z], Length(SearchInfo[X, Z]));
end;
AddMethod(PrecompGetCodec(PChar(CodecSearch[X, Y].Codec), 0, False));
end;
end;
end;
end;
procedure SearchFree(Funcs: PPrecompFuncs);
var
X, Y, Z: Integer;
begin
for X := Low(CodecEnabled) to High(CodecEnabled) do
if CodecEnabled[X] then
begin
for Y := Low(SearchInfo[X]) to High(SearchInfo[X]) do
SetLength(SearchInfo[X, Y], 0);
SetLength(SearchInfo[X], 0);
SetLength(SearchCount[X], 0);
end;
end;
function SearchParse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
begin
Result := False;
end;
procedure SearchScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
var
I: Integer;
J: Word;
X, Y, Z: Integer;
Pos, LSize: NativeInt;
SI: _StrInfo1;
SS: PSearchStruct;
MD5: TMD5;
Digest: TMD5Digest;
MD5Checked: Boolean;
begin
for I := Low(CodecSearch) to High(CodecSearch) do
if CodecEnabled[I] then
begin
Pos := 0;
LSize := Size - Pred(Int64.Size);
while Pos < LSize do
begin
J := PWord(Input + Pos)^;
if (SearchCount[I, J] > 0) and
(CodecSearch[I, 0].HashSize <= (SizeEx - Pos)) then
begin
MD5Checked := False;
for X := 0 to SearchCount[I, J] - 1 do
begin
if (PInt64(Input + Pos)^ = CodecSearch[I, SearchInfo[I, J, X]]
.SearchInt) then
begin
if not MD5Checked then
begin
MD5.Full(Input + Pos, CodecSearch[I, 0].HashSize, Digest);
MD5Checked := True;
end;
// fix this
if CompareMem(@CodecSearch[I, SearchInfo[I, J, X]].HashDigest[0],
@Digest[0], sizeof(TMD5Digest)) then
begin
SS := @CodecSearch[I, SearchInfo[I, J, X]];
Output(Instance, nil, -1);
for Y := Low(SS^.EntryList) to High(SS^.EntryList) do
begin
SI.Position := Pos + SS^.EntryList[Y].Position;
SI.OldSize := SS^.EntryList[Y].OldSize;
SI.NewSize := SS^.EntryList[Y].NewSize;
SI.Option := 0;
SI.Resource := SS^.Resource;
if System.Pos(SPrecompSep2, SS^.Codec) > 0 then
SI.Status := TStreamStatus.Predicted
else
SI.Status := TStreamStatus.None;
Add(Instance, @SI, PChar(SS^.Codec), nil);
end;
end;
end;
end;
end;
Inc(Pos);
end;
end;
end;
function SearchScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
begin
Result := False;
end;
function SearchProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
begin
Result := False;
end;
function SearchRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
begin
Result := False;
end;
var
I, J, K: Integer;
S: String;
Bytes: TBytes;
FStream: TFileStream;
I32: Integer;
SearchStruct: PSearchStruct;
initialization
SearchList := TDirectory.GetFiles(ExtractFilePath(Utils.GetModuleName), '*.xtl',
TSearchOption.soTopDirectoryOnly);
for I := Low(SearchList) to High(SearchList) do
begin
FStream := TFileStream.Create(SearchList[I], fmShareDenyNone);
try
if FStream.Size >= 4 then
begin
FStream.ReadBuffer(I32, I32.Size);
if (I32 = XTOOL_DB) then
begin
if FStream.Position < FStream.Size then
begin
J := Length(CodecSearch);
SetLength(CodecSearch, Succ(J));
S := ChangeFileExt(ExtractFileName(SearchList[I]), '');
Insert(S, Codec.Names, Length(Codec.Names));
end;
while FStream.Position < FStream.Size do
begin
New(SearchStruct);
SearchStruct^.Name := S;
FStream.ReadBuffer(SearchStruct^.SearchInt,
SearchStruct^.SearchInt.Size);
FStream.ReadBuffer(SearchStruct^.HashSize,
SearchStruct^.HashSize.Size);
FStream.ReadBuffer(SearchStruct^.HashDigest, sizeof(THash128));
FStream.ReadBuffer(I32, I32.Size);
SetLength(Bytes, I32);
FStream.ReadBuffer(Bytes[0], I32);
SearchStruct^.Codec := StringOf(Bytes);
Insert(SearchStruct^, CodecSearch[J], Length(CodecSearch[J]));
FStream.ReadBuffer(I32, I32.Size);
K := Pred(Length(CodecSearch[J]));
SetLength(CodecSearch[J, K].EntryList, I32);
FStream.ReadBuffer(CodecSearch[J, K].EntryList[0],
I32 * sizeof(TEntryStruct));
end;
end;
end;
finally
FStream.Free;
end;
end;
Codec.Initialised := False;
Codec.Init := @SearchInit;
Codec.Free := @SearchFree;
Codec.Parse := @SearchParse;
Codec.Scan1 := @SearchScan1;
Codec.Scan2 := @SearchScan2;
Codec.Process := @SearchProcess;
Codec.Restore := @SearchRestore;
SetLength(SearchInfo, Length(CodecSearch));
SetLength(SearchCount, Length(CodecSearch));
SetLength(CodecAvailable, Length(CodecSearch));
SetLength(CodecEnabled, Length(CodecSearch));
end.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,729 @@
unit PrecompZLib;
interface
uses
ZLibDLL, ReflateDLL, PreflateDLL, GrittibanzliDLL,
Utils,
PrecompUtils,
System.SysUtils, System.StrUtils, System.Classes, System.Math;
var
Codec: TPrecompressor;
implementation
const
ZlibCodecs: array of PChar = ['zlib', 'reflate', 'preflate', 'grittibanzli'];
CODEC_COUNT = 4;
ZLIB_CODEC = 0;
REFLATE_CODEC = 1;
PREFLATE_CODEC = 2;
GRITTIBANZLI_CODEC = 3;
const
Z_WINBITS = 7;
Z_SCANBYTES = 16;
Z_WORKMEM = 65536;
Z_MINSIZE = 128;
Z_BLKSIZE = 512;
R_LEVEL = 6;
R_WORKMEM = 65536;
P_HIFSIZE = 1048576;
G_HIFSIZE = 8338608;
var
SOList: array of array [0 .. CODEC_COUNT - 1] of TSOList;
ZStream1: array of array [1 .. 9, 1 .. 9, 1 .. 7] of z_stream;
ZStream2: array of array [0 .. 7] of z_stream;
ZWinBits: Integer = Z_WINBITS;
RefInst1, RefInst2: array of Pointer;
CodecAvailable, CodecEnabled: TArray<Boolean>;
Storage: TArray<TMemoryStream>;
function ZlibInit(Command: PChar; Count: Integer; Funcs: PPrecompFuncs)
: Boolean;
var
I: Integer;
Options: TArray<Integer>;
S: String;
W, X, Y, Z: 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);
SetLength(Storage, Count);
for X := Low(Storage) to High(Storage) do
Storage[X] := TMemoryStream.Create;
for X := Low(CodecAvailable) to High(CodecAvailable) do
begin
CodecAvailable[X] := False;
CodecEnabled[X] := False;
end;
CodecAvailable[ZLIB_CODEC] := ZLibDLL.DLLLoaded;
CodecAvailable[REFLATE_CODEC] := ReflateDLL.DLLLoaded;
CodecAvailable[PREFLATE_CODEC] := PreflateDLL.DLLLoaded;
CodecAvailable[GRITTIBANZLI_CODEC] := GrittibanzliDLL.DLLLoaded;
X := 0;
while Funcs^.GetCodec(Command, X, False) <> '' do
begin
S := Funcs^.GetCodec(Command, X, False);
if (CompareText(S, ZlibCodecs[ZLIB_CODEC]) = 0) and ZLibDLL.DLLLoaded then
begin
CodecEnabled[ZLIB_CODEC] := True;
if Funcs^.GetParam(Command, X, 'l') <> '' then
for I := Low(SOList) to High(SOList) do
SOList[I][ZLIB_CODEC].Update
([StrToInt(Funcs^.GetParam(Command, X, 'l'))], True);
if Funcs^.GetParam(Command, X, 'w') <> '' then
ZWinBits := EnsureRange(StrToInt(Funcs^.GetParam(Command, X, 'w'))
- 8, 1, 7);
end
else if (CompareText(S, ZlibCodecs[REFLATE_CODEC]) = 0) and ReflateDLL.DLLLoaded
then
begin
CodecEnabled[REFLATE_CODEC] := True;
if Funcs^.GetParam(Command, X, 'l') <> '' then
for I := Low(SOList) to High(SOList) do
SOList[I][REFLATE_CODEC].Update
([StrToInt(Funcs^.GetParam(Command, X, 'l'))], True);
end
else if (CompareText(S, ZlibCodecs[PREFLATE_CODEC]) = 0) and PreflateDLL.DLLLoaded
then
CodecEnabled[PREFLATE_CODEC] := True
else if (CompareText(S, ZlibCodecs[GRITTIBANZLI_CODEC]) = 0) and
GrittibanzliDLL.DLLLoaded then
CodecEnabled[GRITTIBANZLI_CODEC] := True;
Inc(X);
end;
if CodecAvailable[ZLIB_CODEC] then
begin
SetLength(ZStream1, Count);
for W := Low(ZStream1) to High(ZStream1) do
for X := Low(ZStream1[W]) to High(ZStream1[W]) do
for Y := Low(ZStream1[W, X]) to High(ZStream1[W, X]) do
for Z := Low(ZStream1[W, X, Y]) to High(ZStream1[W, X, Y]) do
begin
FillChar(ZStream1[W, X, Y, Z], SizeOf(z_stream), 0);
deflateInit2(ZStream1[W, X, Y, Z], X, Z_DEFLATED, -(Z + 8), Y,
Z_DEFAULT_STRATEGY);
end;
end;
if CodecAvailable[REFLATE_CODEC] then
begin
SetLength(RefInst1, Count);
SetLength(RefInst2, Count);
for X := Low(RefInst1) to High(RefInst1) do
begin
RefInst1[X] := raw2hif_Alloc;
RefInst2[X] := hif2raw_Alloc;
end;
end;
if not BoolArray(CodecAvailable, False) then
begin
SetLength(ZStream2, Count);
for X := Low(ZStream2) to High(ZStream2) do
for Y := Low(ZStream2[X]) to High(ZStream2[X]) do
begin
FillChar(ZStream2[X, Y], SizeOf(z_stream), 0);
inflateInit2(ZStream2[X, Y], -(Y + 8));
end;
for X := Low(SOList) to High(SOList) do
for Y := Low(SOList[X]) to High(SOList[X]) do
begin
SetLength(Options, 0);
case Y of
ZLIB_CODEC:
for I := 11 to 99 do
if I mod 10 <> 0 then
Insert(I, Options, Length(Options));
REFLATE_CODEC:
Options := [R_LEVEL];
end;
if SOList[X, Y].Count = 0 then
SOList[X, Y].Update(Options);
end;
end
else
Result := False;
end;
procedure ZlibFree(Funcs: PPrecompFuncs);
var
W, X, Y, Z: Integer;
begin
for X := Low(SOList) to High(SOList) do
for Y := Low(SOList[X]) to High(SOList[X]) do
SOList[X, Y].Free;
for X := Low(Storage) to High(Storage) do
Storage[X].Free;
if CodecAvailable[ZLIB_CODEC] then
begin
for W := Low(ZStream1) to High(ZStream1) do
for X := Low(ZStream1[W]) to High(ZStream1[W]) do
for Y := Low(ZStream1[W, X]) to High(ZStream1[W, X]) do
for Z := Low(ZStream1[W, X, Y]) to High(ZStream1[W, X, Y]) do
deflateEnd(ZStream1[W, X, Y, Z]);
end;
if CodecAvailable[REFLATE_CODEC] then
begin
for X := Low(RefInst1) to High(RefInst1) do
begin
raw2hif_Free(RefInst1[X]);
hif2raw_Free(RefInst2[X]);
end;
end;
if not BoolArray(CodecAvailable, False) then
begin
for X := Low(ZStream2) to High(ZStream2) do
for Y := Low(ZStream2[X]) to High(ZStream2[X]) do
inflateEnd(ZStream2[X, Y]);
end;
end;
function ZlibParse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
var
S: String;
I: Integer;
begin
Result := False;
Option^ := 0;
SetBits(Option^, ZWinBits, 12, 3);
I := 0;
while Funcs^.GetCodec(Command, I, False) <> '' do
begin
S := Funcs^.GetCodec(Command, I, False);
if (CompareText(S, ZlibCodecs[ZLIB_CODEC]) = 0) and ZLibDLL.DLLLoaded then
begin
SetBits(Option^, 0, 0, 5);
if Funcs^.GetParam(Command, I, 'l') <> '' then
SetBits(Option^, StrToInt(Funcs^.GetParam(Command, I, 'l')), 5, 7);
if Funcs^.GetParam(Command, I, 'w') <> '' then
SetBits(Option^, EnsureRange(StrToInt(Funcs^.GetParam(Command, I, 'w'))
- 8, 1, 7), 12, 3);
Result := True;
end
else if (CompareText(S, ZlibCodecs[REFLATE_CODEC]) = 0) and ReflateDLL.DLLLoaded
then
begin
SetBits(Option^, 1, 0, 5);
if Funcs^.GetParam(Command, I, 'l') <> '' then
SetBits(Option^, StrToInt(Funcs^.GetParam(Command, I, 'l')), 5, 7);
Result := True;
end
else if (CompareText(S, ZlibCodecs[PREFLATE_CODEC]) = 0) and PreflateDLL.DLLLoaded
then
begin
SetBits(Option^, 2, 0, 5);
Result := True;
end
else if (CompareText(S, ZlibCodecs[GRITTIBANZLI_CODEC]) = 0) and
GrittibanzliDLL.DLLLoaded then
begin
SetBits(Option^, 3, 0, 5);
Result := True;
end;
Inc(I);
end;
end;
procedure ZlibScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
var
Buffer: PByte;
Pos: NativeInt;
Res: Integer;
I: Integer;
ZStream: z_streamp;
IsZlib: Boolean;
Level: Integer;
WinBits: Byte;
ScanBytes: Integer;
SI: _StrInfo1;
DI: TDepthInfo;
DS: TPrecompCmd;
LastIn, LastOut: cardinal;
begin
if BoolArray(CodecEnabled, False) then
exit;
DI := Funcs^.GetDepthInfo(Instance);
DS := Funcs^.GetCodec(DI.Codec, 0, False);
if DS <> '' then
if IndexTextW(@DS[0], ZlibCodecs) < 0 then
exit;
Pos := 0;
Buffer := Funcs^.Allocator(Instance, Z_WORKMEM);
IsZlib := False;
while Pos < Size do
begin
Res := PInteger(Input + Pos)^;
for I := 1 to 3 do
begin
if LongRec(Res).Bytes[0] <> LongRec(Res).Bytes[I] then
break;
end;
if (I = 3) or (LongRec(Res).Lo = LongRec(Res).Hi) then
begin
Inc(Pos);
continue;
end;
if (Pos >= 2) and ((Input + Pos - 2)^ and $F = 8) and
((Input + Pos - 1)^ and $20 = 0) and
(EndianSwap(PWord(Input + Pos - 2)^) mod $1F = 0) then
begin
WinBits := (Input + Pos - 2)^ shr 4;
if WinBits in [0 .. 7] then
begin
ZStream := @ZStream2[Instance, WinBits];
Level := (Input + Pos - 1)^ shr $6;
IsZlib := True;
ScanBytes := Z_MINSIZE;
end;
end;
IsZlib := False;
if IsZlib or ((Input + Pos)^ and 7 in [$4, $5]) then
begin
if not IsZlib then
begin
WinBits := ZWinBits;
ZStream := @ZStream2[Instance, WinBits];
Level := -1;
end;
if WinBits = 7 then
ScanBytes := Z_SCANBYTES;
IsZlib := False;
LastIn := 0;
LastOut := 0;
ZStream^.next_in := (Input + Pos);
ZStream^.avail_in := ScanBytes;
ZStream^.next_out := Buffer;
ZStream^.avail_out := Z_WORKMEM;
inflateReset(ZStream^);
Res := inflate(ZStream^, Z_SYNC_FLUSH);
if (Res in [Z_OK, Z_STREAM_END]) and (ZStream^.total_in = ScanBytes) then
begin
Output(Instance, nil, 0);
I := Z_WORKMEM - ZStream^.avail_out;
Output(Instance, Buffer, I);
ZStream^.avail_in := (SizeEx - Pos) - Z_SCANBYTES;
while Res <> Z_STREAM_END do
begin
ZStream^.next_out := Buffer;
ZStream^.avail_out := Z_WORKMEM;
Res := inflate(ZStream^, Z_BLOCK);
if not(Res in [Z_OK, Z_STREAM_END]) then
begin
if (LastIn >= Z_MINSIZE) then
Res := Z_STREAM_END;
break;
end;
LastIn := ZStream^.total_in;
LastOut := ZStream^.total_out;
I := Z_WORKMEM - ZStream^.avail_out;
Output(Instance, Buffer, I);
end;
if (Res = Z_STREAM_END) { and (ZStream^.total_out > ZStream^.total_in) }
then
begin
SI.Position := Pos;
SI.OldSize := LastIn;
SI.NewSize := LastOut;
SI.Option := 0;
if Level >= 0 then
begin
case Level of
0:
SetBits(SI.Option, 1, 5, 7);
1:
SetBits(SI.Option, 5, 5, 7);
2:
SetBits(SI.Option, 6, 5, 7);
3:
SetBits(SI.Option, 9, 5, 7);
end;
SI.Status := TStreamStatus.Predicted;
end
else
SI.Status := TStreamStatus.None;
SetBits(SI.Option, WinBits, 12, 3);
for I := Low(CodecEnabled) to High(CodecEnabled) do
begin
if (I = ZLIB_CODEC) and (WinBits = 0) then
SetBits(SI.Option, 1, 12, 3);
SetBits(SI.Option, I, 0, 5);
if CodecEnabled[I] then
begin
Add(Instance, @SI, nil, nil);
break;
end;
end;
Inc(Pos, SI.OldSize);
continue;
end
else
Output(Instance, nil, 0);
end;
end;
Inc(Pos);
end;
end;
function ZLibScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
Res: Integer;
ZStream: z_streamp;
begin
Result := False;
if StreamInfo^.NewSize <= 0 then
exit;
Buffer := Funcs^.Allocator(Instance, StreamInfo^.NewSize);
ZStream := @ZStream2[Instance, GetBits(StreamInfo^.Option, 12, 3)];
ZStream^.next_in := Input;
ZStream^.avail_in := StreamInfo^.OldSize;
ZStream^.next_out := Buffer;
ZStream^.avail_out := StreamInfo^.NewSize;
inflateReset(ZStream^);
Res := inflate(ZStream^, Z_FULL_FLUSH);
if (Res = Z_STREAM_END) and (ZStream^.total_out = StreamInfo^.NewSize) then
begin
Output(Instance, Buffer, ZStream^.total_out);
Result := True;
end;
end;
function ZlibProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
function IsValidLevel(CLevel, ZLevel: Integer): Boolean;
begin
case CLevel of
1, 6:
if CLevel = ZLevel then
Result := True;
2 .. 5:
if ZLevel = 5 then
Result := True;
7 .. 9:
if ZLevel = 9 then
Result := True;
else
Result := False;
end;
end;
var
Buffer, Ptr: PByte;
Res1, Res2: Integer;
L, M: Integer;
I, J: Integer;
X: Integer;
ZStream: z_streamp;
HR: Pointer;
Verified: Boolean;
CRC: cardinal;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
case X of
ZLIB_CODEC:
begin
Buffer := Funcs^.Allocator(Instance, Z_WORKMEM);
SOList[Instance][ZLIB_CODEC].Index := 0;
while SOList[Instance][ZLIB_CODEC].Get(I) >= 0 do
begin
L := I div 10;
M := I mod 10;
if StreamInfo^.Status = TStreamStatus.Predicted then
begin
if InRange(GetBits(StreamInfo^.Option, 5, 7), 1, 9) then
begin
if not IsValidLevel(L, GetBits(StreamInfo^.Option, 5, 7)) then
continue;
end
else
begin
if GetBits(StreamInfo^.Option, 5, 7) <> I then
continue;
{ I := GetBits(StreamInfo^.Option, 5, 7);
SOList[Instance][ZLIB_CODEC].Add(I);
Result := True;
break; }
end;
end;
ZStream := @ZStream1[Instance, L, M,
GetBits(StreamInfo^.Option, 12, 3)];
ZStream^.next_in := NewInput;
ZStream^.avail_in := StreamInfo^.NewSize;
deflateReset(ZStream^);
repeat
ZStream^.next_out := Buffer;
ZStream^.avail_out := Z_BLKSIZE;
Res1 := deflate(ZStream^, Z_FINISH);
if Res1 < 0 then
raise EZCompressionError.Create(string(_z_errmsg[2 - Res1]))
at ReturnAddress;
Res2 := Z_BLKSIZE - ZStream^.avail_out;
Verified := CompareMem(PByte(OldInput) + ZStream^.total_out - Res2,
Buffer, Res2);
if not Verified then
break;
until (ZStream^.avail_in = 0) and (ZStream^.avail_out > 0);
if Verified and (Res1 = Z_STREAM_END) then
begin
SetBits(StreamInfo^.Option, I, 5, 7);
SOList[Instance][ZLIB_CODEC].Add(I);
Result := True;
break;
end;
end;
if Result = False then
begin
if CodecEnabled[REFLATE_CODEC] or CodecEnabled[PREFLATE_CODEC] or
CodecEnabled[GRITTIBANZLI_CODEC] then
begin
if CodecEnabled[REFLATE_CODEC] then
SetBits(StreamInfo^.Option, REFLATE_CODEC, 0, 5)
else if CodecEnabled[PREFLATE_CODEC] then
SetBits(StreamInfo^.Option, PREFLATE_CODEC, 0, 5)
else
SetBits(StreamInfo^.Option, GRITTIBANZLI_CODEC, 0, 5);
Result := ZlibProcess(Instance, Depth, OldInput, NewInput,
StreamInfo, Output, Funcs);
end;
end;
end;
REFLATE_CODEC:
begin
Buffer := Funcs^.Allocator(Instance, R_WORKMEM * 2);
Storage[Instance].Position := 0;
HR := RefInst1[Instance];
if StreamInfo^.Status = TStreamStatus.Predicted then
L := GetBits(StreamInfo^.Option, 5, 7)
else
L := R_LEVEL;
if L > 9 then
L := L div 10;
L := EnsureRange(L, 1, 9);
M := 0;
I := 0;
raw2hif_Init(HR, L);
while True do
begin
Res1 := raw2hif_Loop(HR);
if (Res1 in [0, 2]) or (Res1 > 3) then
begin
Res2 := raw2hif_getoutlen(HR);
Output(Instance, Buffer, Res2);
Storage[Instance].WriteBuffer(Buffer^, Res2);
raw2hif_addbuf(HR, Buffer, R_WORKMEM);
end;
if (Res1 = 3) or (Res1 = 0) then
begin
Res2 := raw2hif_getou2len(HR);
Inc(M, Res2);
raw2hif_addbuf(HR, Buffer + R_WORKMEM, R_WORKMEM);
if Res1 = 0 then
break;
end;
if (Res1 = 1) then
begin
Res2 := Min(StreamInfo^.OldSize - I, R_WORKMEM);
raw2hif_addbuf(HR, PByte(OldInput) + I, Res2);
Inc(I, Res2);
end;
end;
if M = StreamInfo^.NewSize then
begin
{ HR := RefInst2[Instance];
I := 0;
J := 0;
M := 0;
CRC := 0;
M := Storage[Instance].Position;
Ptr := Storage[Instance].Memory;
hif2raw_Init(HR, L);
while True do
begin
Res1 := hif2raw_Loop(HR);
if (Res1 in [0, 2]) or (Res1 > 3) then
begin
Res2 := hif2raw_getoutlen(HR);
if Res2 > 0 then
CRC := Hash32(CRC, Buffer, Res2);
hif2raw_addbuf(HR, Buffer, R_WORKMEM);
if Res1 = 0 then
break;
end;
if Res1 = 1 then
begin
Res2 := Min(M - J, R_WORKMEM);
hif2raw_addbuf(HR, Ptr + J, Res2);
Inc(J, Res2);
end;
if Res1 = 3 then
begin
Res2 := Min(StreamInfo^.NewSize - I, R_WORKMEM);
hif2raw_addbuf(HR, PByte(NewInput) + I, Res2);
Inc(I, Res2);
end;
end;
if CRC = Hash32(0, OldInput, StreamInfo^.OldSize) then
begin }
SetBits(StreamInfo^.Option, L, 5, 7);
Result := True;
// end;
end;
end;
PREFLATE_CODEC:
begin
Res1 := StreamInfo^.NewSize;
Res2 := P_HIFSIZE;
Buffer := Funcs^.Allocator(Instance, Res2);
if preflate_decode(OldInput, StreamInfo^.OldSize, NewInput, @Res1,
Buffer, @Res2) then
begin
Output(Instance, Buffer, Res2);
Result := True;
end;
end;
GRITTIBANZLI_CODEC:
begin
Res1 := StreamInfo^.NewSize;
Res2 := G_HIFSIZE;
Buffer := Funcs^.Allocator(Instance, Res2);
if Grittibanzli(OldInput, StreamInfo^.OldSize, NewInput, @Res1, Buffer,
@Res2) then
begin
Output(Instance, Buffer, Res2);
Result := True;
end;
end;
end;
end;
function ZlibRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
Res1, Res2: Integer;
L, M: Integer;
I, J: Integer;
X: Integer;
ZStream: z_streamp;
HR: Pointer;
begin
Result := False;
X := GetBits(StreamInfo.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
case X of
ZLIB_CODEC:
begin
Buffer := Funcs^.Allocator(Instance, Z_WORKMEM);
L := GetBits(StreamInfo.Option, 5, 7) div 10;
M := GetBits(StreamInfo.Option, 5, 7) mod 10;
ZStream := @ZStream1[Instance, L, M, GetBits(StreamInfo.Option, 12, 3)];
ZStream^.next_in := Input;
ZStream^.avail_in := StreamInfo.NewSize;
deflateReset(ZStream^);
repeat
ZStream^.next_out := Buffer;
ZStream^.avail_out := Z_WORKMEM;
Res1 := deflate(ZStream^, Z_FINISH);
if Res1 < 0 then
raise EZCompressionError.Create(string(_z_errmsg[2 - Res1]))
at ReturnAddress;
Res2 := Z_WORKMEM - ZStream^.avail_out;
Output(Instance, Buffer, Res2);
until (ZStream^.avail_in = 0) and (ZStream^.avail_out > 0);
Result := True;
end;
REFLATE_CODEC:
begin
Buffer := Funcs^.Allocator(Instance, R_WORKMEM);
HR := RefInst2[Instance];
I := 0;
J := 0;
hif2raw_Init(HR, GetBits(StreamInfo.Option, 5, 7));
while True do
begin
Res1 := hif2raw_Loop(HR);
if (Res1 in [0, 2]) or (Res1 > 3) then
begin
Res2 := hif2raw_getoutlen(HR);
Output(Instance, Buffer, Res2);
hif2raw_addbuf(HR, Buffer, R_WORKMEM);
if Res1 = 0 then
break;
end;
if Res1 = 1 then
begin
Res2 := Min(StreamInfo.ExtSize - J, R_WORKMEM);
hif2raw_addbuf(HR, PByte(InputExt) + J, Res2);
Inc(J, Res2);
end;
if Res1 = 3 then
begin
Res2 := Min(StreamInfo.NewSize - I, R_WORKMEM);
hif2raw_addbuf(HR, PByte(Input) + I, Res2);
Inc(I, Res2);
end;
end;
Result := True;
end;
PREFLATE_CODEC:
begin
Res1 := StreamInfo.OldSize;
Buffer := Funcs^.Allocator(Instance, Res1);
if preflate_reencode(Input, StreamInfo.NewSize, InputExt,
StreamInfo.ExtSize, Buffer, @Res1) then
begin
Output(Instance, Buffer, Res1);
Result := True;
end;
end;
GRITTIBANZLI_CODEC:
begin
Res1 := StreamInfo.OldSize;
Buffer := Funcs^.Allocator(Instance, Res1);
if Ungrittibanzli(Input, StreamInfo.NewSize, InputExt,
StreamInfo.ExtSize, Buffer, @Res1) then
begin
Output(Instance, Buffer, Res1);
Result := True;
end;
end;
end;
end;
var
I: Integer;
initialization
Codec.Names := [];
for I := Low(ZlibCodecs) to High(ZlibCodecs) do
begin
Codec.Names := Codec.Names + [ZlibCodecs[I]];
StockMethods.Add(ZlibCodecs[I]);
end;
Codec.Initialised := False;
Codec.Init := @ZlibInit;
Codec.Free := @ZlibFree;
Codec.Parse := @ZlibParse;
Codec.Scan1 := @ZlibScan1;
Codec.Scan2 := @ZLibScan2;
Codec.Process := @ZlibProcess;
Codec.Restore := @ZlibRestore;
SetLength(CodecAvailable, Length(Codec.Names));
SetLength(CodecEnabled, Length(Codec.Names));
end.

View File

@@ -0,0 +1,332 @@
unit PrecompZSTD;
interface
uses
ZSTDDLL, XDeltaDLL,
Utils,
PrecompUtils,
System.SysUtils, System.Classes, System.Math;
var
Codec: TPrecompressor;
implementation
const
ZSTDCodecs: array of PChar = ['zstd'];
CODEC_COUNT = 1;
ZSTD_CODEC = 0;
var
SOList: array of array [0 .. CODEC_COUNT - 1] of TSOList;
cctx, dctx: array of Pointer;
// cdict, ddict: Pointer;
DStream: TMemoryStream;
CodecAvailable, CodecEnabled: TArray<Boolean>;
function ZSTDInit(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] := ZSTDDLL.DLLLoaded;
X := 0;
while Funcs^.GetCodec(Command, X, False) <> '' do
begin
S := Funcs^.GetCodec(Command, X, False);
if (CompareText(S, ZSTDCodecs[ZSTD_CODEC]) = 0) and ZSTDDLL.DLLLoaded then
begin
CodecEnabled[ZSTD_CODEC] := True;
if Funcs^.GetParam(Command, X, 'l') <> '' then
for I := Low(SOList) to High(SOList) do
SOList[I][ZSTD_CODEC].Update
([StrToInt(Funcs^.GetParam(Command, X, 'l'))], True);
end;
Inc(X);
end;
if CodecAvailable[ZSTD_CODEC] then
begin
SetLength(cctx, Count);
SetLength(dctx, Count);
for X := Low(cctx) to High(cctx) do
begin
cctx[X] := ZSTD_createCCtx;
dctx[X] := ZSTD_createDCtx;
end;
end;
SetLength(Options, 0);
for I := 1 to 22 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 ZSTDFree(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;
if CodecAvailable[ZSTD_CODEC] then
begin
for X := Low(cctx) to High(cctx) do
begin
ZSTD_freeCCtx(cctx[X]);
ZSTD_freeDCtx(dctx[X]);
end;
end;
end;
function ZSTDParse(Command: PChar; Option: PInteger;
Funcs: PPrecompFuncs): Boolean;
var
S: String;
I: Integer;
begin
Result := False;
Option^ := 0;
I := 0;
while Funcs^.GetCodec(Command, I, False) <> '' do
begin
S := Funcs^.GetCodec(Command, I, False);
if (CompareText(S, ZSTDCodecs[ZSTD_CODEC]) = 0) and ZSTDDLL.DLLLoaded then
begin
SetBits(Option^, 0, 0, 5);
if Funcs^.GetParam(Command, I, 'l') <> '' then
SetBits(Option^, StrToInt(Funcs^.GetParam(Command, I, 'l')), 5, 7);
Result := True;
end;
Inc(I);
end;
end;
procedure ZSTDScan1(Instance, Depth: Integer; Input: PByte;
Size, SizeEx: NativeInt; Output: _PrecompOutput; Add: _PrecompAdd;
Funcs: PPrecompFuncs);
var
Buffer: PByte;
Pos: NativeInt;
X, Y, Z: Integer;
SI: _StrInfo1;
begin
if BoolArray(CodecEnabled, False) then
exit;
Pos := 0;
while Pos < Size do
begin
if PCardinal(Input + Pos)^ = $FD2FB528 then
begin
X := ZSTD_findFrameCompressedSize(Input + Pos, SizeEx - Pos);
if X > 0 then
begin
Z := ZSTD_findDecompressedSize(Input + Pos, X);
if Z <= 0 then
begin
Inc(Pos);
continue;
end;
Buffer := Funcs^.Allocator(Instance, Z);
Y := ZSTD_decompressDCtx(dctx[Instance], Buffer, Z, Input + Pos, X);
// Y := ZSTD_decompress_usingDDict(dctx[Instance], Buffer, Z, Input + Pos, X, ddict);
if (X < Y) then
begin
Output(Instance, Buffer, Y);
SI.Position := Pos;
SI.OldSize := X;
SI.NewSize := Y;
SI.Option := 0;
SI.Status := TStreamStatus.None;
Add(Instance, @SI, nil, nil);
Inc(Pos, SI.OldSize);
continue;
end;
end;
end;
Inc(Pos);
end;
end;
function ZSTDScan2(Instance, Depth: Integer; Input: Pointer; Size: NativeInt;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
Res: Integer;
begin
Result := False;
if StreamInfo^.NewSize <= 0 then
exit;
Buffer := Funcs^.Allocator(Instance, StreamInfo^.NewSize);
Res := ZSTD_decompressDCtx(dctx[Instance], Buffer, StreamInfo^.NewSize, Input,
StreamInfo^.OldSize);
{ Res := ZSTD_decompress_usingDDict(dctx[Instance], Buffer, StreamInfo^.NewSize,
Input, StreamInfo^.OldSize, ddict); }
if Res = StreamInfo^.NewSize then
begin
Output(Instance, Buffer, Res);
Result := True;
end;
end;
function ZSTDProcess(Instance, Depth: Integer; OldInput, NewInput: Pointer;
StreamInfo: PStrInfo2; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
I: Integer;
X: Integer;
Res1: Integer;
Res2: NativeUInt;
// Inp: ZSTD_inBuffer;
// Oup: ZSTD_outBuffer;
// Progress: NativeInt;
begin
Result := False;
X := GetBits(StreamInfo^.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
Buffer := Funcs^.Allocator(Instance, 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;
case X of
ZSTD_CODEC:
Res1 := ZSTD_compressCCtx(cctx[Instance], Buffer, StreamInfo^.NewSize,
NewInput, StreamInfo^.NewSize, I);
{ Res1 := ZSTD_compress_usingCDict(cctx[Instance], Buffer,
StreamInfo^.NewSize, NewInput, StreamInfo^.NewSize, cdict); }
{ begin
Progress := 0;
Oup.dst := Buffer;
Oup.Size := StreamInfo^.NewSize;
Oup.Pos := 0;
ZSTD_initCStream(cctx[Instance], I);
while Progress < StreamInfo^.NewSize do
begin
Inp.src := PByte(NewInput) + Progress;
Inp.Size := Min(StreamInfo^.NewSize - Progress, 32768);
Inp.Pos := 0;
if ZSTD_compressStream(cctx[Instance], @Oup, @Inp) > 0 then
begin
ZSTD_flushStream(cctx[Instance], @Oup);
Inc(Progress, Inp.Size)
end
else
exit;
end;
ZSTD_endStream(cctx[Instance], @Oup);
Res1 := Oup.Pos;
end; }
end;
Result := (Res1 = StreamInfo^.OldSize) and CompareMem(OldInput, Buffer,
StreamInfo^.OldSize);
if Result then
begin
SetBits(StreamInfo^.Option, I, 5, 7);
SOList[Instance][X].Add(I);
break;
end;
end;
if (Result = False) and ((StreamInfo^.Status = TStreamStatus.Predicted) or
(SOList[Instance][X].Count = 1)) then
begin
Buffer := Funcs^.Allocator(Instance, Res1 + Max(StreamInfo^.OldSize, Res1));
Res2 := PrecompEncodePatch(OldInput, StreamInfo^.OldSize, Buffer, Res1,
Buffer + Res1, Max(StreamInfo^.OldSize, Res1));
if (Res2 > 0) and ((Res2 / Max(StreamInfo^.OldSize, Res1)) <= DIFF_TOLERANCE)
then
begin
Output(Instance, Buffer + Res1, Res2);
SetBits(StreamInfo^.Option, 1, 31, 1);
SOList[Instance][X].Add(I);
Result := True;
end;
end;
end;
function ZSTDRestore(Instance, Depth: Integer; Input, InputExt: Pointer;
StreamInfo: _StrInfo3; Output: _PrecompOutput; Funcs: PPrecompFuncs): Boolean;
var
Buffer: PByte;
X: Integer;
Res1: Integer;
Res2: NativeUInt;
begin
Result := False;
X := GetBits(StreamInfo.Option, 0, 5);
if BoolArray(CodecAvailable, False) or (CodecAvailable[X] = False) then
exit;
Buffer := Funcs^.Allocator(Instance, StreamInfo.NewSize);
case X of
ZSTD_CODEC:
Res1 := ZSTD_compressCCtx(cctx[Instance], Buffer, StreamInfo.NewSize,
Input, StreamInfo.NewSize, GetBits(StreamInfo.Option, 5, 7));
{ Res1 := ZSTD_compress_usingCDict(cctx[Instance], Buffer,
StreamInfo.NewSize, Input, StreamInfo.NewSize, cdict); }
end;
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);
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
{ DStream := TMemoryStream.Create;
DStream.LoadFromFile(ExtractFilePath(Utils.GetModuleName) + 'frostbite3_dict.dat');
cdict := ZSTD_createCDict(DStream.Memory, DStream.Size, 19);
ddict := ZSTD_createDDict(DStream.Memory, DStream.Size); }
Codec.Names := [];
for I := Low(ZSTDCodecs) to High(ZSTDCodecs) do
begin
Codec.Names := Codec.Names + [ZSTDCodecs[I]];
StockMethods.Add(ZSTDCodecs[I]);
end;
Codec.Initialised := False;
Codec.Init := @ZSTDInit;
Codec.Free := @ZSTDFree;
Codec.Parse := @ZSTDParse;
Codec.Scan1 := @ZSTDScan1;
Codec.Scan2 := @ZSTDScan2;
Codec.Process := @ZSTDProcess;
Codec.Restore := @ZSTDRestore;
SetLength(CodecAvailable, Length(Codec.Names));
SetLength(CodecEnabled, Length(Codec.Names));
end.