xtool/contrib/CoreCipher/Source/CoreCompress.pas

1404 lines
43 KiB
ObjectPascal

{ * Compressor * }
{ ****************************************************************************** }
{ * https://zpascal.net * }
{ * https://github.com/PassByYou888/zAI * }
{ * https://github.com/PassByYou888/ZServer4D * }
{ * https://github.com/PassByYou888/PascalString * }
{ * https://github.com/PassByYou888/zRasterization * }
{ * https://github.com/PassByYou888/CoreCipher * }
{ * https://github.com/PassByYou888/zSound * }
{ * https://github.com/PassByYou888/zChinese * }
{ * https://github.com/PassByYou888/zExpression * }
{ * https://github.com/PassByYou888/zGameWare * }
{ * https://github.com/PassByYou888/zAnalysis * }
{ * https://github.com/PassByYou888/FFMPEG-Header * }
{ * https://github.com/PassByYou888/zTranslate * }
{ * https://github.com/PassByYou888/InfiniteIoT * }
{ * https://github.com/PassByYou888/FastMD5 * }
{ ****************************************************************************** }
unit CoreCompress;
{$INCLUDE zDefine.inc}
interface
uses Math, Types, CoreClasses;
type
PPCCInt8 = ^PCCInt8;
PCCInt8 = ^TCCInt8;
TCCInt8 = ShortInt;
PPCCUInt8 = ^PCCUInt8;
PCCUInt8 = ^TCCUInt8;
TCCUInt8 = Byte;
PCCInt16 = ^TCCInt16;
TCCInt16 = SmallInt;
PCCUInt16 = ^TCCUInt16;
TCCUInt16 = Word;
PCCInt32 = ^TCCInt32;
TCCInt32 = Integer;
PCCUInt32 = ^TCCUInt32;
TCCUInt32 = Cardinal;
PCCInt64 = ^TCCInt64;
TCCInt64 = Int64;
PCCUInt64 = ^TCCUInt64;
TCCUInt64 = UInt64;
PCCPtr = ^TCCPtr;
TCCPtr = Pointer;
TCCPtrUInt = nativeUInt;
TCCPtrInt = NativeInt;
PPCCPtrInt = ^PCCPtrInt;
PCCPtrUInt = ^TCCPtrUInt;
PCCPtrInt = ^TCCPtrInt;
PCCSizeUInt = ^TCCSizeUInt;
TCCSizeUInt = TCCPtrUInt;
PCCSizeInt = ^TCCSizeInt;
TCCSizeInt = TCCPtrInt;
PCCNativeUInt = ^TCCNativeUInt;
TCCNativeUInt = TCCPtrUInt;
PCCNativeInt = ^TCCNativeInt;
TCCNativeInt = TCCPtrInt;
PCCSize = ^TCCSizeUInt;
TCCSize = TCCPtrUInt;
PCCUInt8Array = ^TCCUInt8Array;
TCCUInt8Array = array [0 .. MaxInt div SizeOf(TCCUInt8) - 1] of TCCUInt8;
PPCCUInt64Record = ^PCCUInt64Record;
PCCUInt64Record = ^TCCUInt64Record;
TCCUInt64Record = packed record
case Boolean of
False: ( {$IFDEF BIG_ENDIAN}Hi, Lo{$ELSE}Lo, Hi{$ENDIF}: TCCUInt32;);
True: (Value: TCCUInt64;);
end;
TCompressor = class(TCoreClassObject)
private const
ChunkHeadSize = $3000;
ChunkSize = $FFFF - ChunkHeadSize;
PrepareBuffSize = $FFFF;
public
constructor Create; reintroduce; virtual;
destructor Destroy; override;
function Compress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt; virtual;
function Decompress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt; virtual;
procedure CompressStream(sour: TCoreClassStream; StartPos, EndPos: NativeInt; CompressTo: TCoreClassStream);
procedure DecompressStream(sour, DecompressTo: TCoreClassStream);
end;
TCompressorClass = class of TCompressor;
TCompressorDeflate = class(TCompressor)
private const
HashBits = 16;
HashSize = 1 shl HashBits;
HashMask = HashSize - 1;
HashShift = 32 - HashBits;
WindowSize = 32768;
WindowMask = WindowSize - 1;
MinMatch = 3;
MaxMatch = 258;
MaxOffset = 32768;
HashRef_ENDIAN_B30 = {$IF defined(BIG_ENDIAN)}$FFFFFF00{$ELSE}$00FFFFFF{$IFEND};
{$IFNDEF BIG_ENDIAN}
MultiplyDeBruijnBytePosition: array [0 .. 31] of TCCUInt8 = (0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1);
{$ENDIF}
//
LengthCodes: array [0 .. 28, 0 .. 3] of TCCUInt32 =
( // Code, ExtraBits, Min, Max
(257, 0, 3, 3), (258, 0, 4, 4), (259, 0, 5, 5),
(260, 0, 6, 6), (261, 0, 7, 7), (262, 0, 8, 8),
(263, 0, 9, 9), (264, 0, 10, 10), (265, 1, 11, 12),
(266, 1, 13, 14), (267, 1, 15, 16), (268, 1, 17, 18),
(269, 2, 19, 22), (270, 2, 23, 26), (271, 2, 27, 30),
(272, 2, 31, 34), (273, 3, 35, 42), (274, 3, 43, 50),
(275, 3, 51, 58), (276, 3, 59, 66), (277, 4, 67, 82),
(278, 4, 83, 98), (279, 4, 99, 114), (280, 4, 115, 130),
(281, 5, 131, 162), (282, 5, 163, 194), (283, 5, 195, 226),
(284, 5, 227, 257), (285, 0, 258, 258)
);
DistanceCodes: array [0 .. 29, 0 .. 3] of TCCUInt32 =
( // Code, ExtraBits, Min, Max
(0, 0, 1, 1), (1, 0, 2, 2), (2, 0, 3, 3),
(3, 0, 4, 4), (4, 1, 5, 6), (5, 1, 7, 8),
(6, 2, 9, 12), (7, 2, 13, 16), (8, 3, 17, 24),
(9, 3, 25, 32), (10, 4, 33, 48), (11, 4, 49, 64),
(12, 5, 65, 96), (13, 5, 97, 128), (14, 6, 129, 192),
(15, 6, 193, 256), (16, 7, 257, 384), (17, 7, 385, 512),
(18, 8, 513, 768), (19, 8, 769, 1024), (20, 9, 1025, 1536),
(21, 9, 1537, 2048), (22, 10, 2049, 3072), (23, 10, 3073, 4096),
(24, 11, 4097, 6144), (25, 11, 6145, 8192), (26, 12, 8193, 12288),
(27, 12, 12289, 16384), (28, 13, 16385, 24576), (29, 13, 24577, 32768)
);
MirrorBytes: array [TCCUInt8] of TCCUInt8 =
(
$00, $80, $40, $C0, $20, $A0, $60, $E0,
$10, $90, $50, $D0, $30, $B0, $70, $F0,
$08, $88, $48, $C8, $28, $A8, $68, $E8,
$18, $98, $58, $D8, $38, $B8, $78, $F8,
$04, $84, $44, $C4, $24, $A4, $64, $E4,
$14, $94, $54, $D4, $34, $B4, $74, $F4,
$0C, $8C, $4C, $CC, $2C, $AC, $6C, $EC,
$1C, $9C, $5C, $DC, $3C, $BC, $7C, $FC,
$02, $82, $42, $C2, $22, $A2, $62, $E2,
$12, $92, $52, $D2, $32, $B2, $72, $F2,
$0A, $8A, $4A, $CA, $2A, $AA, $6A, $EA,
$1A, $9A, $5A, $DA, $3A, $BA, $7A, $FA,
$06, $86, $46, $C6, $26, $A6, $66, $E6,
$16, $96, $56, $D6, $36, $B6, $76, $F6,
$0E, $8E, $4E, $CE, $2E, $AE, $6E, $EE,
$1E, $9E, $5E, $DE, $3E, $BE, $7E, $FE,
$01, $81, $41, $C1, $21, $A1, $61, $E1,
$11, $91, $51, $D1, $31, $B1, $71, $F1,
$09, $89, $49, $C9, $29, $A9, $69, $E9,
$19, $99, $59, $D9, $39, $B9, $79, $F9,
$05, $85, $45, $C5, $25, $A5, $65, $E5,
$15, $95, $55, $D5, $35, $B5, $75, $F5,
$0D, $8D, $4D, $CD, $2D, $AD, $6D, $ED,
$1D, $9D, $5D, $DD, $3D, $BD, $7D, $FD,
$03, $83, $43, $C3, $23, $A3, $63, $E3,
$13, $93, $53, $D3, $33, $B3, $73, $F3,
$0B, $8B, $4B, $CB, $2B, $AB, $6B, $EB,
$1B, $9B, $5B, $DB, $3B, $BB, $7B, $FB,
$07, $87, $47, $C7, $27, $A7, $67, $E7,
$17, $97, $57, $D7, $37, $B7, $77, $F7,
$0F, $8F, $4F, $CF, $2F, $AF, $6F, $EF,
$1F, $9F, $5F, $DF, $3F, $BF, $7F, $FF
);
CLCIndex: array [0 .. 18] of TCCUInt8 = (16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15);
type
PHashTable = ^THashTable;
THashTable = array [0 .. HashSize - 1] of PCCUInt8;
PChainTable = ^TChainTable;
TChainTable = array [0 .. WindowSize - 1] of TCCPtr;
PTree = ^TTree;
TTree = packed record
Table: array [0 .. 15] of TCCUInt16;
Translation: array [0 .. 287] of TCCUInt16;
end;
PBuffer = ^TBuffer;
TBuffer = array [0 .. 65535] of TCCUInt8;
PLengths = ^TLengths;
TLengths = array [0 .. 288 + 32 - 1] of TCCUInt8;
POffsets = ^TOffsets;
TOffsets = array [0 .. 15] of TCCUInt16;
TBits = array [0 .. 29] of TCCUInt8;
PBits = ^TBits;
TBase = array [0 .. 29] of TCCUInt16;
PBase = ^TBase;
var
fHashTable: THashTable;
fChainTable: TChainTable;
fLengthCodesLookUpTable: array [0 .. 258] of TCCInt32;
fDistanceCodesLookUpTable: array [0 .. 32768] of TCCInt32;
fSymbolLengthTree: TTree;
fDistanceTree: TTree;
fFixedSymbolLengthTree: TTree;
fFixedDistanceTree: TTree;
fLengthBits: TBits;
fDistanceBits: TBits;
fLengthBase: TBase;
fDistanceBase: TBase;
fCodeTree: TTree;
fLengths: TLengths;
fWithHeader: Boolean;
fGreedy: Boolean;
fSkipStrength: TCCUInt32;
fMaxSteps: TCCUInt32;
public
constructor Create; override;
destructor Destroy; override;
function Compress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt; override;
function Decompress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt; override;
property WithHeader: Boolean read fWithHeader write fWithHeader;
property Greedy: Boolean read fGreedy write fGreedy;
property SkipStrength: TCCUInt32 read fSkipStrength write fSkipStrength;
property MaxSteps: TCCUInt32 read fMaxSteps write fMaxSteps;
end;
TCompressorBRRC = class(TCompressor)
private const
FlagModel = 0;
LiteralModel = 2;
SizeModels = 258;
public
constructor Create; override;
destructor Destroy; override;
function Compress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt; override;
function Decompress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt; override;
end;
function CoreCompressStream(Compressor: TCompressor; sour: TCoreClassStream; ComTo: TCoreClassStream): Boolean;
function CoreDecompressStream(Compressor: TCompressor; sour: TCoreClassStream; DeTo: TCoreClassStream): Boolean;
function DeflateCompressStream(sour: TCoreClassStream; ComTo: TCoreClassStream): Boolean;
function DeflateDecompressStream(sour: TCoreClassStream; DeTo: TCoreClassStream): Boolean;
function BRRCCompressStream(sour: TCoreClassStream; ComTo: TCoreClassStream): Boolean;
function BRRCDecompressStream(sour: TCoreClassStream; DeTo: TCoreClassStream): Boolean;
implementation
uses MemoryStream64;
function CoreCompressStream(Compressor: TCompressor; sour: TCoreClassStream; ComTo: TCoreClassStream): Boolean;
begin
try
Compressor.CompressStream(sour, 0, sour.Size, ComTo);
Result := True;
except
Result := False;
end;
end;
function CoreDecompressStream(Compressor: TCompressor; sour: TCoreClassStream; DeTo: TCoreClassStream): Boolean;
begin
try
Compressor.DecompressStream(sour, DeTo);
Result := True;
except
Result := False;
end;
end;
function DeflateCompressStream(sour: TCoreClassStream; ComTo: TCoreClassStream): Boolean;
var
c: TCompressorDeflate;
begin
c := TCompressorDeflate.Create;
Result := CoreCompressStream(c, sour, ComTo);
DisposeObject(c);
end;
function DeflateDecompressStream(sour: TCoreClassStream; DeTo: TCoreClassStream): Boolean;
var
c: TCompressorDeflate;
begin
c := TCompressorDeflate.Create;
Result := CoreDecompressStream(c, sour, DeTo);
DisposeObject(c);
end;
function BRRCCompressStream(sour: TCoreClassStream; ComTo: TCoreClassStream): Boolean;
var
c: TCompressorBRRC;
begin
c := TCompressorBRRC.Create;
Result := CoreCompressStream(c, sour, ComTo);
DisposeObject(c);
end;
function BRRCDecompressStream(sour: TCoreClassStream; DeTo: TCoreClassStream): Boolean;
var
c: TCompressorBRRC;
begin
c := TCompressorBRRC.Create;
Result := CoreDecompressStream(c, sour, DeTo);
DisposeObject(c);
end;
procedure BytewiseMemoryMove(const aSource; var aDestination; const aLength: TCCSizeUInt);
var
index: TCCSizeUInt;
Source, Destination: PCCUInt8Array;
begin
if aLength > 0 then
begin
Source := TCCPtr(@aSource);
Destination := TCCPtr(@aDestination);
for index := 0 to aLength - 1 do
begin
Destination^[index] := Source^[index];
end;
end;
end;
procedure RLELikeSideEffectAwareMemoryMove(const aSource; var aDestination; const aLength: TCCSizeUInt);
begin
if aLength > 0 then
begin
if (TCCSizeUInt(TCCPtr(@aSource)) + aLength) <= TCCSizeUInt(TCCPtr(@aDestination)) then
// Non-overlapping, so we an use an optimized memory move function
CopyPtr(@aSource, @aDestination, aLength)
else
// Overlapping, so we must do copy byte-wise for to get the free RLE-like side-effect included
BytewiseMemoryMove(aSource, aDestination, aLength);
end;
end;
{$IFDEF RangeCheck}{$R-}{$ENDIF}
{$IFNDEF fpc}
function BSRDWord(Value: TCCUInt32): TCCUInt32;
const
BSRDebruijn32Multiplicator = TCCUInt32($07C4ACDD);
BSRDebruijn32Shift = 27;
BSRDebruijn32Mask = 31;
BSRDebruijn32Table: array [0 .. 31] of TCCInt32 = (0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31);
begin
if Value = 0 then
begin
Result := 255;
end
else
begin
Value := Value or (Value shr 1);
Value := Value or (Value shr 2);
Value := Value or (Value shr 4);
Value := Value or (Value shr 8);
Value := Value or (Value shr 16);
Result := BSRDebruijn32Table[((Value * BSRDebruijn32Multiplicator) shr BSRDebruijn32Shift) and BSRDebruijn32Mask];
end;
end;
{$IFEND}
function SARLongint(Value, Shift: TCCInt32): TCCInt32;
begin
Shift := Shift and 31;
Result := (TCCUInt32(Value) shr Shift) or (TCCUInt32(TCCInt32(TCCUInt32(-TCCUInt32(TCCUInt32(Value) shr 31)) and TCCUInt32(-TCCUInt32(Ord(Shift <> 0) and 1)))) shl (32 - Shift));
end;
function SARInt64(Value: TCCInt64; Shift: TCCInt32): TCCInt64;
begin
Shift := Shift and 63;
Result := (TCCInt64(Value) shr Shift) or (TCCInt64(TCCInt64(TCCInt64(-TCCInt64(TCCInt64(Value) shr 63)) and TCCInt64(-TCCInt64(Ord(Shift <> 0) and 1)))) shl (63 - Shift));
end;
constructor TCompressor.Create;
begin
inherited Create;
end;
destructor TCompressor.Destroy;
begin
inherited Destroy;
end;
function TCompressor.Compress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt;
begin
Result := 0;
end;
function TCompressor.Decompress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt;
begin
Result := 0;
end;
procedure TCompressor.CompressStream(sour: TCoreClassStream; StartPos, EndPos: NativeInt; CompressTo: TCoreClassStream);
type
TPrepareBuff = array [0 .. PrepareBuffSize + 2] of Byte;
PPrepareBuff = ^TPrepareBuff;
var
buff: array [0 .. ChunkSize] of Byte;
PrepareBuffPtr: PPrepareBuff;
siz: Int64;
j: NativeInt;
Num: NativeInt;
Rest: NativeInt;
begin
siz := EndPos - StartPos;
if siz > 0 then
begin
CompressTo.write(siz, 8);
sour.Position := StartPos;
new(PrepareBuffPtr);
if siz > ChunkSize then
begin
Num := siz div ChunkSize;
Rest := siz mod ChunkSize;
for j := 0 to Num - 1 do
begin
sour.read(buff[0], ChunkSize);
PWORD(@(PrepareBuffPtr^[0]))^ := Compress(@buff[0], ChunkSize, @PrepareBuffPtr^[2], PrepareBuffSize);
CompressTo.write(PrepareBuffPtr^[0], PWORD(@(PrepareBuffPtr^[0]))^ + 2);
end;
if Rest > 0 then
begin
sour.read(buff[0], Rest);
PWORD(@(PrepareBuffPtr^[0]))^ := Compress(@buff[0], Rest, @PrepareBuffPtr^[2], PrepareBuffSize);
CompressTo.write(PrepareBuffPtr^[0], PWORD(@(PrepareBuffPtr^[0]))^ + 2);
end;
end
else
begin
sour.read(buff[0], siz);
PWORD(@(PrepareBuffPtr^[0]))^ := Compress(@buff[0], siz, @PrepareBuffPtr^[2], PrepareBuffSize);
CompressTo.write(PrepareBuffPtr^[0], PWORD(@(PrepareBuffPtr^[0]))^ + 2);
end;
Dispose(PrepareBuffPtr);
end;
end;
procedure TCompressor.DecompressStream(sour, DecompressTo: TCoreClassStream);
var
siz, cSiz: Int64;
bufSiz, deBufSiz: Word;
buff, decryptBuff: Pointer;
begin
if sour.Position + 10 < sour.Size then
begin
sour.read(siz, 8);
cSiz := 0;
buff := GetMemory(PrepareBuffSize);
decryptBuff := GetMemory(PrepareBuffSize);
while cSiz < siz do
begin
if sour.read(bufSiz, 2) <> 2 then
Break;
if sour.read(buff^, bufSiz) <> bufSiz then
Break;
deBufSiz := Decompress(buff, bufSiz, decryptBuff, PrepareBuffSize);
DecompressTo.write(decryptBuff^, deBufSiz);
inc(cSiz, deBufSiz);
end;
FreeMemory(buff);
FreeMemory(decryptBuff);
end;
end;
constructor TCompressorDeflate.Create;
procedure BuildFixedTrees(var aLT, aDT: TTree);
var
i: TCCInt32;
begin
for i := 0 to 6 do
begin
aLT.Table[i] := 0;
end;
aLT.Table[7] := 24;
aLT.Table[8] := 152;
aLT.Table[9] := 112;
for i := 0 to 23 do
aLT.Translation[i] := 256 + i;
for i := 0 to 143 do
aLT.Translation[24 + i] := i;
for i := 0 to 7 do
aLT.Translation[168 + i] := 280 + i;
for i := 0 to 111 do
aLT.Translation[176 + i] := 144 + i;
for i := 0 to 4 do
aDT.Table[i] := 0;
aDT.Table[5] := 32;
for i := 0 to 31 do
aDT.Translation[i] := i;
end;
procedure BuildBitsBase(aBits: PCCUInt8Array; aBase: PCCUInt16; aDelta, aFirst: TCCInt32);
var
i, Sum: TCCInt32;
begin
for i := 0 to aDelta - 1 do
aBits^[i] := 0;
for i := 0 to (30 - aDelta) - 1 do
aBits^[i + aDelta] := i div aDelta;
Sum := aFirst;
for i := 0 to 29 do
begin
aBase^ := Sum;
inc(aBase);
inc(Sum, 1 shl aBits^[i]);
end;
end;
var
index, ValueIndex: TCCInt32;
begin
inherited Create;
for index := 0 to length(LengthCodes) - 1 do
for ValueIndex := IfThen(index = 0, 0, LengthCodes[index, 2]) to LengthCodes[index, 3] do
fLengthCodesLookUpTable[ValueIndex] := index;
for index := 0 to length(DistanceCodes) - 1 do
for ValueIndex := IfThen(index = 0, 0, DistanceCodes[index, 2]) to DistanceCodes[index, 3] do
fDistanceCodesLookUpTable[ValueIndex] := index;
FillPtrByte(@fLengthBits, SizeOf(TBits), 0);
FillPtrByte(@fDistanceBits, SizeOf(TBits), 0);
FillPtrByte(@fLengthBase, SizeOf(TBase), 0);
FillPtrByte(@fDistanceBase, SizeOf(TBase), 0);
FillPtrByte(@fFixedSymbolLengthTree, SizeOf(TTree), 0);
FillPtrByte(@fFixedDistanceTree, SizeOf(TTree), 0);
BuildFixedTrees(fFixedSymbolLengthTree, fFixedDistanceTree);
BuildBitsBase(TCCPtr(@fLengthBits[0]), PCCUInt16(TCCPtr(@fLengthBase[0])), 4, 3);
BuildBitsBase(TCCPtr(@fDistanceBits[0]), PCCUInt16(TCCPtr(@fDistanceBase[0])), 2, 1);
fLengthBits[28] := 0;
fLengthBase[28] := 258;
fWithHeader := False;
fGreedy := False;
fSkipStrength := 32;
fMaxSteps := 128;
end;
destructor TCompressorDeflate.Destroy;
begin
inherited Destroy;
end;
function TCompressorDeflate.Compress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt;
var
OutputBits, CountOutputBits: TCCUInt32;
DestLen: TCCSizeUInt;
OK: Boolean;
procedure DoOutputBits(const aBits, aCountBits: TCCUInt32);
begin
Assert((CountOutputBits + aCountBits) <= 32);
OutputBits := OutputBits or (aBits shl CountOutputBits);
inc(CountOutputBits, aCountBits);
while CountOutputBits >= 8 do
begin
if DestLen < aOutLimit then
begin
PCCUInt8Array(aOutData)^[DestLen] := OutputBits and $FF;
inc(DestLen);
end
else
begin
OK := False;
end;
OutputBits := OutputBits shr 8;
dec(CountOutputBits, 8);
end;
end;
procedure DoOutputLiteral(const AValue: TCCUInt8);
begin
case AValue of
0 .. 143: DoOutputBits(MirrorBytes[$30 + AValue], 8);
else DoOutputBits((MirrorBytes[$90 + (AValue - 144)] shl 1) or 1, 9);
end;
end;
procedure DoOutputCopy(const aDistance, aLength: TCCUInt32);
var
Remain, ToDo, index: TCCUInt32;
begin
Remain := aLength;
while Remain > 0 do
begin
case Remain of
0 .. 258: ToDo := Remain;
259 .. 260: ToDo := Remain - 3;
else ToDo := 258;
end;
dec(Remain, ToDo);
index := fLengthCodesLookUpTable[Min(Max(ToDo, 0), 258)];
if LengthCodes[index, 0] <= 279 then
DoOutputBits(MirrorBytes[(LengthCodes[index, 0] - 256) shl 1], 7)
else
DoOutputBits(MirrorBytes[$C0 + (LengthCodes[index, 0] - 280)], 8);
if LengthCodes[index, 1] <> 0 then
DoOutputBits(ToDo - LengthCodes[index, 2], LengthCodes[index, 1]);
index := fDistanceCodesLookUpTable[Min(Max(aDistance, 0), 32768)];
DoOutputBits(MirrorBytes[DistanceCodes[index, 0] shl 3], 5);
if DistanceCodes[index, 1] <> 0 then
DoOutputBits(aDistance - DistanceCodes[index, 2], DistanceCodes[index, 1]);
end;
end;
procedure OutputStartBlock;
begin
DoOutputBits(1, 1); // Final block
DoOutputBits(1, 2); // Static huffman block
end;
procedure OutputEndBlock;
begin
DoOutputBits(0, 7); // Close block
DoOutputBits(0, 7); // Make sure all bits are flushed
end;
function Adler32(const aData: TCCPtr; const aLength: TCCUInt32): TCCUInt32;
const
Base = 65521;
MaximumCountAtOnce = 5552;
var
Buf: PCCUInt8;
Remain, s1, s2, ToDo, index: TCCUInt32;
begin
s1 := 1;
s2 := 0;
Buf := aData;
Remain := aLength;
while Remain > 0 do
begin
if Remain < MaximumCountAtOnce then
ToDo := Remain
else
ToDo := MaximumCountAtOnce;
dec(Remain, ToDo);
for index := 1 to ToDo do
begin
inc(s1, TCCUInt8(Buf^));
inc(s2, s1);
inc(Buf);
end;
s1 := s1 mod Base;
s2 := s2 mod Base;
end;
Result := (s2 shl 16) or s1;
end;
var
CurrentPointer, EndPointer, EndSearchPointer, Head, CurrentPossibleMatch: PCCUInt8;
BestMatchDistance, BestMatchLength, MatchLength, CheckSum, Step, Difference, Offset, UnsuccessfulFindMatchAttempts: TCCUInt32;
HashTableItem: PPCCUInt8;
begin
OK := True;
DestLen := 0;
OutputBits := 0;
CountOutputBits := 0;
if fWithHeader then
begin
DoOutputBits($78, 8); // CMF
DoOutputBits($9C, 8); // FLG Default Compression
end;
OutputStartBlock;
FillPtrByte(@fHashTable, SizeOf(THashTable), 0);
FillPtrByte(@fChainTable, SizeOf(TChainTable), 0);
CurrentPointer := aInData;
EndPointer := TCCPtr(TCCPtrUInt(TCCPtrUInt(CurrentPointer) + TCCPtrUInt(aInSize)));
EndSearchPointer := TCCPtr(TCCPtrUInt((TCCPtrUInt(CurrentPointer) + TCCPtrUInt(aInSize)) - TCCPtrUInt(TCCInt64(Max(TCCInt64(MinMatch), TCCInt64(SizeOf(TCCUInt32)))))));
UnsuccessfulFindMatchAttempts := TCCUInt32(1) shl fSkipStrength;
while TCCPtrUInt(CurrentPointer) < TCCPtrUInt(EndSearchPointer) do
begin
HashTableItem := @fHashTable[((((PCCUInt32(TCCPtr(CurrentPointer))^ and TCCUInt32(HashRef_ENDIAN_B30){$IF defined(BIG_ENDIAN)} shr 8{$IFEND})) * TCCUInt32($1E35A7BD)) shr HashShift) and HashMask];
Head := HashTableItem^;
CurrentPossibleMatch := Head;
BestMatchDistance := 0;
BestMatchLength := 1;
Step := 0;
while Assigned(CurrentPossibleMatch) and
(TCCPtrUInt(CurrentPointer) > TCCPtrUInt(CurrentPossibleMatch)) and
(TCCPtrInt(TCCPtrUInt(TCCPtrUInt(CurrentPointer) - TCCPtrUInt(CurrentPossibleMatch))) < TCCPtrInt(MaxOffset)) do
begin
Difference := PCCUInt32(TCCPtr(@PCCUInt8Array(CurrentPointer)^[0]))^ xor PCCUInt32(TCCPtr(@PCCUInt8Array(CurrentPossibleMatch)^[0]))^;
if (Difference and TCCUInt32(HashRef_ENDIAN_B30)) = 0 then
begin
if (BestMatchLength <= (TCCPtrUInt(EndPointer) - TCCPtrUInt(CurrentPointer))) and
(PCCUInt8Array(CurrentPointer)^[BestMatchLength - 1] = PCCUInt8Array(CurrentPossibleMatch)^[BestMatchLength - 1]) then
begin
MatchLength := MinMatch;
while ((TCCPtrUInt(@PCCUInt8Array(CurrentPointer)^[MatchLength]) and (SizeOf(TCCUInt32) - 1)) <> 0) and
((TCCPtrUInt(@PCCUInt8Array(CurrentPointer)^[MatchLength]) < TCCPtrUInt(EndPointer))) and
(PCCUInt8Array(CurrentPointer)^[MatchLength] = PCCUInt8Array(CurrentPossibleMatch)^[MatchLength]) do
inc(MatchLength);
while (TCCPtrUInt(@PCCUInt8Array(CurrentPointer)^[MatchLength + (SizeOf(TCCUInt32) - 1)]) < TCCPtrUInt(EndPointer)) do
begin
Difference := PCCUInt32(TCCPtr(@PCCUInt8Array(CurrentPointer)^[MatchLength]))^ xor PCCUInt32(TCCPtr(@PCCUInt8Array(CurrentPossibleMatch)^[MatchLength]))^;
if Difference = 0 then
begin
inc(MatchLength, SizeOf(TCCUInt32));
end
else
begin
{$IF defined(BIG_ENDIAN)}
if (Difference shr 16) <> 0 then
inc(MatchLength, not(Difference shr 24))
else
inc(MatchLength, 2 + (not(Difference shr 8)));
{$ELSE}
inc(MatchLength, MultiplyDeBruijnBytePosition[TCCUInt32(TCCUInt32(Difference and (-Difference)) * TCCUInt32($077CB531)) shr 27]);
{$IFEND}
Break;
end;
end;
if BestMatchLength < MatchLength then
begin
BestMatchDistance := TCCPtrUInt(TCCPtrUInt(CurrentPointer) - TCCPtrUInt(CurrentPossibleMatch));
BestMatchLength := MatchLength;
end;
end;
end;
inc(Step);
if Step < fMaxSteps then
CurrentPossibleMatch := fChainTable[(TCCPtrUInt(CurrentPossibleMatch) - TCCPtrUInt(aInData)) and WindowMask]
else
Break;
end;
if (BestMatchDistance > 0) and (BestMatchLength > 1) then
begin
DoOutputCopy(BestMatchDistance, BestMatchLength);
UnsuccessfulFindMatchAttempts := TCCUInt32(1) shl fSkipStrength;
end
else
begin
if fSkipStrength > 31 then
begin
DoOutputLiteral(CurrentPointer^);
end
else
begin
Step := UnsuccessfulFindMatchAttempts shr fSkipStrength;
Offset := 0;
while (Offset < Step) and ((TCCPtrUInt(CurrentPointer) + Offset) < TCCPtrUInt(EndSearchPointer)) do
begin
DoOutputLiteral(PCCUInt8Array(CurrentPointer)^[Offset]);
inc(Offset);
end;
BestMatchLength := Offset;
inc(UnsuccessfulFindMatchAttempts, Ord(UnsuccessfulFindMatchAttempts < TCCUInt32($FFFFFFFF)) and 1);
end;
end;
if not OK then
Break;
HashTableItem^ := CurrentPointer;
fChainTable[(TCCPtrUInt(CurrentPointer) - TCCPtrUInt(aInData)) and WindowMask] := Head;
if fGreedy then
begin
inc(CurrentPointer);
dec(BestMatchLength);
while (BestMatchLength > 0) and (TCCPtrUInt(CurrentPointer) < TCCPtrUInt(EndSearchPointer)) do
begin
HashTableItem := @fHashTable[((((PCCUInt32(TCCPtr(CurrentPointer))^ and TCCUInt32(HashRef_ENDIAN_B30){$IF defined(BIG_ENDIAN)} shr 8{$IFEND})) * TCCUInt32($1E35A7BD)) shr HashShift) and HashMask];
Head := HashTableItem^;
HashTableItem^ := CurrentPointer;
fChainTable[(TCCPtrUInt(CurrentPointer) - TCCPtrUInt(aInData)) and WindowMask] := Head;
inc(CurrentPointer);
dec(BestMatchLength);
end;
end;
inc(CurrentPointer, BestMatchLength);
end;
while TCCPtrUInt(CurrentPointer) < TCCPtrUInt(EndPointer) do
begin
DoOutputLiteral(CurrentPointer^);
if not OK then
Break;
inc(CurrentPointer);
end;
OutputEndBlock;
if fWithHeader then
begin
CheckSum := Adler32(aInData, aInSize);
if (DestLen + 4) < aOutLimit then
begin
PCCUInt8Array(aOutData)^[DestLen + 0] := (CheckSum shr 24) and $FF;
PCCUInt8Array(aOutData)^[DestLen + 1] := (CheckSum shr 16) and $FF;
PCCUInt8Array(aOutData)^[DestLen + 2] := (CheckSum shr 8) and $FF;
PCCUInt8Array(aOutData)^[DestLen + 3] := (CheckSum shr 0) and $FF;
inc(DestLen, 4);
end;
end;
if OK then
Result := DestLen
else
Result := 0;
end;
function TCompressorDeflate.Decompress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt;
var
Tag, BitCount: TCCUInt32;
Source, SourceEnd: PCCUInt8;
dest: PCCUInt8;
DestLen: TCCSizeUInt;
function Adler32(aData: TCCPtr; aLength: TCCUInt32): TCCUInt32;
const
Base = 65521;
NMAX = 5552;
var
Buf: PCCUInt8;
s1, s2, k, i: TCCUInt32;
begin
s1 := 1;
s2 := 0;
Buf := aData;
while aLength > 0 do
begin
if aLength < NMAX then
k := aLength
else
k := NMAX;
dec(aLength, k);
for i := 1 to k do
begin
inc(s1, TCCUInt8(Buf^));
inc(s2, s1);
inc(Buf);
end;
s1 := s1 mod Base;
s2 := s2 mod Base;
end;
Result := (s2 shl 16) or s1;
end;
procedure BuildTree(var aTree: TTree; aLengths: PCCUInt8Array; aNum: TCCInt32);
var
Offsets: TOffsets;
i: TCCInt32;
Sum: TCCUInt32;
begin
for i := 0 to 15 do
aTree.Table[i] := 0;
for i := 0 to aNum - 1 do
inc(aTree.Table[TCCUInt8(aLengths^[i])]);
aTree.Table[0] := 0;
Sum := 0;
for i := 0 to 15 do
begin
Offsets[i] := Sum;
inc(Sum, aTree.Table[i]);
end;
for i := 0 to aNum - 1 do
if aLengths^[i] <> 0 then
begin
aTree.Translation[Offsets[TCCUInt8(aLengths^[i])]] := i;
inc(Offsets[TCCUInt8(aLengths^[i])]);
end;
end;
function GetBit: TCCUInt32;
begin
if BitCount = 0 then
begin
Tag := TCCUInt8(Source^);
inc(Source);
BitCount := 7;
end
else
dec(BitCount);
Result := Tag and 1;
Tag := Tag shr 1;
end;
function ReadBits(aNum, aBase: TCCUInt32): TCCUInt32;
var
Limit, Mask: TCCUInt32;
begin
Result := 0;
if aNum <> 0 then
begin
Limit := 1 shl aNum;
Mask := 1;
while Mask < Limit do
begin
if GetBit <> 0 then
inc(Result, Mask);
Mask := Mask shl 1;
end;
end;
inc(Result, aBase);
end;
function DecodeSymbol(const aTree: TTree): TCCUInt32;
var
Sum, c, L: TCCInt32;
begin
Sum := 0;
c := 0;
L := 0;
repeat
c := (c * 2) + TCCInt32(GetBit);
inc(L);
inc(Sum, aTree.Table[L]);
dec(c, aTree.Table[L]);
until not(c >= 0);
Result := aTree.Translation[Sum + c];
end;
procedure DecodeTrees(var aLT, aDT: TTree);
var
hlit, hdist, hclen, i, Num, Len, clen, Symbol, Prev: TCCUInt32;
begin
FillPtrByte(@fCodeTree, SizeOf(TTree), 0);
FillPtrByte(@fLengths, SizeOf(TLengths), 0);
hlit := ReadBits(5, 257);
hdist := ReadBits(5, 1);
hclen := ReadBits(4, 4);
for i := 0 to 18 do
fLengths[i] := 0;
for i := 1 to hclen do
begin
clen := ReadBits(3, 0);
fLengths[CLCIndex[i - 1]] := clen;
end;
BuildTree(fCodeTree, TCCPtr(@fLengths[0]), 19);
Num := 0;
while Num < (hlit + hdist) do
begin
Symbol := DecodeSymbol(fCodeTree);
case Symbol of
16:
begin
Prev := fLengths[Num - 1];
Len := ReadBits(2, 3);
while Len > 0 do
begin
fLengths[Num] := Prev;
inc(Num);
dec(Len);
end;
end;
17:
begin
Len := ReadBits(3, 3);
while Len > 0 do
begin
fLengths[Num] := 0;
inc(Num);
dec(Len);
end;
end;
18:
begin
Len := ReadBits(7, 11);
while Len > 0 do
begin
fLengths[Num] := 0;
inc(Num);
dec(Len);
end;
end;
else
begin
fLengths[Num] := Symbol;
inc(Num);
end;
end;
end;
BuildTree(aLT, TCCPtr(@fLengths[0]), hlit);
BuildTree(aDT, TCCPtr(@fLengths[hlit]), hdist);
end;
function InflateBlockData(const aLT, aDT: TTree): Boolean;
var
Symbol: TCCUInt32;
Len, Distance, Offset: TCCInt32;
t: PCCUInt8;
begin
Result := False;
while (TCCPtrUInt(TCCPtr(Source)) < TCCPtrUInt(TCCPtr(SourceEnd))) or (BitCount > 0) do
begin
Symbol := DecodeSymbol(aLT);
if Symbol = 256 then
begin
Result := True;
Break;
end;
if Symbol < 256 then
begin
if (DestLen + 1) <= aOutLimit then
begin
dest^ := TCCUInt8(Symbol);
inc(dest);
inc(DestLen);
end
else
Exit;
end
else
begin
dec(Symbol, 257);
Len := ReadBits(fLengthBits[Symbol], fLengthBase[Symbol]);
Distance := DecodeSymbol(aDT);
Offset := ReadBits(fDistanceBits[Distance], fDistanceBase[Distance]);
if (DestLen + TCCSizeUInt(Len)) <= aOutLimit then
begin
t := TCCPtr(dest);
dec(t, Offset);
RLELikeSideEffectAwareMemoryMove(t^, dest^, Len);
inc(dest, Len);
inc(DestLen, Len);
end
else
Exit;
end;
end;
end;
function InflateUncompressedBlock: Boolean;
var
Len, InvLen: TCCUInt32;
begin
Result := False;
Len := (TCCUInt8(PCCUInt8Array(Source)^[1]) shl 8) or TCCUInt8(PCCUInt8Array(Source)^[0]);
InvLen := (TCCUInt8(PCCUInt8Array(Source)^[3]) shl 8) or TCCUInt8(PCCUInt8Array(Source)^[2]);
if Len <> ((not InvLen) and $FFFF) then
Exit;
inc(Source, 4);
if Len > 0 then
begin
if (DestLen + Len) < aOutLimit then
begin
CopyPtr(Source, dest, Len);
inc(Source, Len);
inc(dest, Len);
end
else
Exit;
end;
BitCount := 0;
inc(DestLen, Len);
Result := True;
end;
function InflateFixedBlock: Boolean;
begin
Result := InflateBlockData(fFixedSymbolLengthTree, fFixedDistanceTree);
end;
function InflateDynamicBlock: Boolean;
begin
FillPtrByte(@fSymbolLengthTree, SizeOf(TTree), 0);
FillPtrByte(@fDistanceTree, SizeOf(TTree), 0);
DecodeTrees(fSymbolLengthTree, fDistanceTree);
Result := InflateBlockData(fSymbolLengthTree, fDistanceTree);
end;
function Uncompress: Boolean;
var
FinalBlock: Boolean;
BlockType: TCCUInt32;
begin
BitCount := 0;
repeat
FinalBlock := GetBit <> 0;
BlockType := ReadBits(2, 0);
case BlockType of
0:
begin
Result := InflateUncompressedBlock;
end;
1:
begin
Result := InflateFixedBlock;
end;
2:
begin
Result := InflateDynamicBlock;
end;
else
begin
Result := False;
end;
end;
until FinalBlock or not Result;
end;
function UncompressZLIB: Boolean;
var
cmf, flg: TCCUInt8;
a32: TCCUInt32;
begin
Result := False;
Source := aInData;
cmf := TCCUInt8(PCCUInt8Array(Source)^[0]);
flg := TCCUInt8(PCCUInt8Array(Source)^[1]);
if ((((cmf shl 8) + flg) mod 31) <> 0) or ((cmf and $F) <> 8) or ((cmf shr 4) > 7) or ((flg and $20) <> 0) then
begin
Exit;
end;
a32 := (TCCUInt8(PCCUInt8Array(Source)^[aInSize - 4]) shl 24) or
(TCCUInt8(PCCUInt8Array(Source)^[aInSize - 3]) shl 16) or
(TCCUInt8(PCCUInt8Array(Source)^[aInSize - 2]) shl 8) or
(TCCUInt8(PCCUInt8Array(Source)^[aInSize - 1]) shl 0);
inc(Source, 2);
SourceEnd := @PCCUInt8Array(Source)^[aInSize - 6];
Result := Uncompress;
if not Result then
begin
Exit;
end;
Result := Adler32(aOutData, DestLen) = a32;
end;
function UncompressDirect: Boolean;
begin
Source := aInData;
SourceEnd := @PCCUInt8Array(Source)^[aInSize];
Result := Uncompress;
end;
begin
dest := aOutData;
DestLen := 0;
Result := 0;
if fWithHeader then
begin
if UncompressZLIB then
begin
Result := DestLen;
end;
end
else
begin
if UncompressDirect then
begin
Result := DestLen;
end;
end;
end;
constructor TCompressorBRRC.Create;
begin
inherited Create;
end;
destructor TCompressorBRRC.Destroy;
begin
inherited Destroy;
end;
function TCompressorBRRC.Compress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt;
var
{$IFNDEF CPU64}Code, {$ENDIF}Range, Cache, CountFFBytes: TCCUInt32;
{$IFDEF CPU64}Code: TCCUInt64; {$ENDIF}
Model: array [0 .. SizeModels - 1] of TCCUInt32;
OK, FirstByte{$IFNDEF CPU64}, Carry{$ENDIF} : Boolean;
DestLen: TCCInt32;
procedure EncoderShift;
{$IFDEF CPU64}
var
Carry: Boolean;
{$ENDIF}
begin
{$IFDEF CPU64}
Carry := PCCUInt64Record(TCCPtr(@Code))^.Hi <> 0; // or (Code shr 32)<>0; or also (Code and TCCUInt64($ffffffff00000000))<>0;
{$ENDIF}
if (Code < $FF000000) or Carry then
begin
if FirstByte then
begin
FirstByte := False;
end
else
begin
if TCCSizeUInt(DestLen) < TCCSizeUInt(aOutLimit) then
begin
PCCUInt8Array(aOutData)^[DestLen] := TCCUInt8(Cache + TCCUInt8(Ord(Carry) and 1));
inc(DestLen);
end
else
begin
OK := False;
Exit;
end;
end;
while CountFFBytes <> 0 do
begin
dec(CountFFBytes);
if TCCSizeUInt(DestLen) < TCCSizeUInt(aOutLimit) then
begin
PCCUInt8Array(aOutData)^[DestLen] := TCCUInt8($FF + TCCUInt8(Ord(Carry) and 1));
inc(DestLen);
end
else
begin
OK := False;
Exit;
end;
end;
Cache := (Code shr 24) and $FF;
end
else
begin
inc(CountFFBytes);
end;
Code := (Code shl 8){$IFDEF CPU64} and TCCUInt32($FFFFFFFF){$ENDIF};
Carry := False;
end;
function EncodeBit(ModelIndex, Move, Bit: TCCInt32): TCCInt32;
var
Bound{$IFNDEF CPU64}, OldCode{$ENDIF}: TCCUInt32;
begin
Bound := (Range shr 12) * Model[ModelIndex];
if Bit = 0 then
begin
Range := Bound;
inc(Model[ModelIndex], (4096 - Model[ModelIndex]) shr Move);
end
else
begin
{$IFNDEF CPU64}
OldCode := Code;
{$ENDIF}
inc(Code, Bound);
{$IFNDEF CPU64}
Carry := Carry or (Code < OldCode);
{$ENDIF}
dec(Range, Bound);
dec(Model[ModelIndex], Model[ModelIndex] shr Move);
end;
while Range < $1000000 do
begin
Range := Range shl 8;
EncoderShift;
end;
Result := Bit;
end;
procedure EncoderFlush;
var
Counter: TCCInt32;
begin
for Counter := 1 to 5 do
EncoderShift;
end;
procedure EncodeTree(ModelIndex, Bits, Move, Value: TCCInt32);
var
Context: TCCInt32;
begin
Context := 1;
while Bits > 0 do
begin
dec(Bits);
Context := (Context shl 1) or EncodeBit(ModelIndex + Context, Move, (Value shr Bits) and 1);
end;
end;
var
CurrentPointer, EndPointer: PCCUInt8;
Len, MinDestLen: TCCInt32;
begin
DestLen := 0;
FirstByte := True;
OK := True;
CountFFBytes := 0;
Range := $FFFFFFFF;
Code := 0;
for Len := 0 to SizeModels - 1 do
begin
Model[Len] := 2048;
end;
CurrentPointer := aInData;
EndPointer := TCCPtr(TCCPtrUInt(TCCPtrUInt(CurrentPointer) + TCCPtrUInt(aInSize)));
while TCCPtrUInt(CurrentPointer) < TCCPtrUInt(EndPointer) do
begin
EncodeBit(FlagModel, 1, 1);
EncodeTree(LiteralModel, 8, 4, PCCUInt8(CurrentPointer)^);
if not OK then
begin
Break;
end;
inc(CurrentPointer);
end;
EncodeBit(FlagModel, 1, 0);
MinDestLen := Max(2, DestLen + 1);
EncoderFlush;
if OK then
begin
while (DestLen > MinDestLen) and (PCCUInt8Array(aOutData)^[DestLen - 1] = 0) do
dec(DestLen);
Result := DestLen;
end
else
Result := 0;
end;
function TCompressorBRRC.Decompress(const aInData: TCCPtr; const aInSize: TCCSizeUInt; const aOutData: TCCPtr; const aOutLimit: TCCSizeUInt): TCCSizeUInt;
var
Code, Range, Position: TCCUInt32;
Model: array [0 .. SizeModels - 1] of TCCUInt32;
OK: Boolean;
function DecodeBit(ModelIndex, Move: TCCInt32): TCCInt32;
var
Bound: TCCUInt32;
begin
Bound := (Range shr 12) * Model[ModelIndex];
if Code < Bound then
begin
Range := Bound;
inc(Model[ModelIndex], (4096 - Model[ModelIndex]) shr Move);
Result := 0;
end
else
begin
dec(Code, Bound);
dec(Range, Bound);
dec(Model[ModelIndex], Model[ModelIndex] shr Move);
Result := 1;
end;
while Range < $1000000 do
begin
if Position < aInSize then
Code := (Code shl 8) or PCCUInt8Array(aInData)^[Position]
else
begin
if Position < (aInSize + 4 + 5) then
Code := Code shl 8
else
begin
OK := False;
Break;
end;
end;
inc(Position);
Range := Range shl 8;
end;
end;
function DecodeTree(ModelIndex, MaxValue, Move: TCCInt32): TCCInt32;
begin
Result := 1;
while OK and (Result < MaxValue) do
Result := (Result shl 1) or DecodeBit(ModelIndex + Result, Move);
dec(Result, MaxValue);
end;
var
DestLen, Value: TCCInt32;
begin
Result := 0;
if aInSize >= 3 then
begin
OK := True;
Code := (PCCUInt8Array(aInData)^[0] shl 24) or
(PCCUInt8Array(aInData)^[1] shl 16) or
(PCCUInt8Array(aInData)^[2] shl 8) or
(PCCUInt8Array(aInData)^[3] shl 0);
Position := 4;
Range := $FFFFFFFF;
for Value := 0 to SizeModels - 1 do
begin
Model[Value] := 2048;
end;
DestLen := 0;
repeat
Value := DecodeBit(FlagModel, 1);
if OK then
begin
if Value <> 0 then
begin
Value := DecodeTree(LiteralModel, 256, 4);
if OK and (TCCSizeUInt(DestLen) < TCCSizeUInt(aOutLimit)) then
begin
PCCUInt8Array(aOutData)^[DestLen] := Value;
inc(DestLen);
end
else
Exit;
end
else
Break;
end
else
Exit;
until False;
Result := DestLen;
end;
end;
{$IFDEF RangeCheck}{$R+}{$ENDIF}
end.