source upload
This commit is contained in:
163
precompressor/PrecompCrypto.pas
Normal file
163
precompressor/PrecompCrypto.pas
Normal 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.
|
408
precompressor/PrecompDLL.pas
Normal file
408
precompressor/PrecompDLL.pas
Normal 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.
|
472
precompressor/PrecompEXE.pas
Normal file
472
precompressor/PrecompEXE.pas
Normal 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.
|
512
precompressor/PrecompINI.pas
Normal file
512
precompressor/PrecompINI.pas
Normal 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.
|
341
precompressor/PrecompLZ4.pas
Normal file
341
precompressor/PrecompLZ4.pas
Normal 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.
|
374
precompressor/PrecompLZO.pas
Normal file
374
precompressor/PrecompLZO.pas
Normal 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.
|
991
precompressor/PrecompMain - Copy.pas
Normal file
991
precompressor/PrecompMain - Copy.pas
Normal 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.
|
1982
precompressor/PrecompMain.pas
Normal file
1982
precompressor/PrecompMain.pas
Normal file
File diff suppressed because it is too large
Load Diff
616
precompressor/PrecompOodle.pas
Normal file
616
precompressor/PrecompOodle.pas
Normal 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.
|
268
precompressor/PrecompSearch.pas
Normal file
268
precompressor/PrecompSearch.pas
Normal 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.
|
1336
precompressor/PrecompUtils.pas
Normal file
1336
precompressor/PrecompUtils.pas
Normal file
File diff suppressed because it is too large
Load Diff
729
precompressor/PrecompZLib.pas
Normal file
729
precompressor/PrecompZLib.pas
Normal 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.
|
332
precompressor/PrecompZSTD.pas
Normal file
332
precompressor/PrecompZSTD.pas
Normal 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.
|
Reference in New Issue
Block a user