source upload
This commit is contained in:
472
sources/lz4.pas
Normal file
472
sources/lz4.pas
Normal file
@@ -0,0 +1,472 @@
|
||||
(*
|
||||
LZ4Delphi
|
||||
Copyright (C) 2015, Jose Pascoa (atelierwebgm@gmail.com)
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
*************************************************************************
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
xxHash - Fast Hash algorithm
|
||||
LZ4 source repository : http://code.google.com/p/lz4/
|
||||
xxHash source repository : http://code.google.com/p/xxhash/
|
||||
Copyright (c) 2011-2014, Yann Collet
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
******************************************************************************
|
||||
*)
|
||||
|
||||
{$POINTERMATH ON}
|
||||
unit lz4;
|
||||
|
||||
interface
|
||||
|
||||
uses Windows;
|
||||
|
||||
const
|
||||
MINMATCH = 4;
|
||||
COPYLENGTH = 8;
|
||||
LASTLITERALS = 5;
|
||||
_MFLIMIT = COPYLENGTH + MINMATCH;
|
||||
MAXD_LOG = 16;
|
||||
MAX_DISTANCE = (1 shl MAXD_LOG) - 1;
|
||||
STEPSIZE = sizeof(size_t);
|
||||
ML_BITS = 4;
|
||||
ML_MASK = (1 shl ML_BITS) - 1;
|
||||
RUN_BITS = 8 - ML_BITS;
|
||||
RUN_MASK = (1 shl RUN_BITS) - 1;
|
||||
|
||||
type
|
||||
ppByte = ^pByte;
|
||||
dict_directive = (noDict = 0, withPrefix64k, usingExtDict);
|
||||
endCondition_directive = (endOnOutputSize = 0, endOnInputSize = 1);
|
||||
earlyEnd_directive = (full = 0, partial = 1);
|
||||
|
||||
function LZ4_decompress_generic(const source: pointer; const dest: pointer;
|
||||
inputSize: integer; outputSize: integer;
|
||||
endOnInput: integer = integer(endOnOutputSize);
|
||||
partialDecoding: integer = integer(full); targetOutputSize: integer = 0;
|
||||
dict: integer = integer(noDict); const lowPrefix: pByte = nil;
|
||||
const dictStart: pByte = nil; const dictSize: size_t = 0): integer;
|
||||
|
||||
implementation
|
||||
|
||||
function LZ4_read_ARCH(const p: pointer): size_t; inline;
|
||||
begin
|
||||
{$IFDEF WIN64}
|
||||
result := size_t(pUint64(p)^)
|
||||
{$ELSE}
|
||||
result := size_t(pCardinal(p)^);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
function LZ4_read32(const memPtr: pointer): cardinal;
|
||||
begin
|
||||
result := pCardinal(memPtr)^;
|
||||
end;
|
||||
|
||||
{$IFDEF WIN64}
|
||||
|
||||
function LZ4_NbCommonBytesx64(value: size_t): cardinal;
|
||||
asm
|
||||
bsf rax, rcx // value comes in rcx register
|
||||
shr eax, 3
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
function LZ4_count(pIn: pByte; pMatch: pByte; const pInLimit: pByte): cardinal;
|
||||
var
|
||||
pStart: pByte;
|
||||
diff: size_t;
|
||||
incValue: cardinal;
|
||||
|
||||
calcedPByte: pByte;
|
||||
begin
|
||||
pStart := pIn;
|
||||
calcedPByte := pInLimit - (STEPSIZE - 1);
|
||||
|
||||
while pIn < calcedPByte do
|
||||
begin
|
||||
diff := LZ4_read_ARCH(pMatch) xor LZ4_read_ARCH(pIn);
|
||||
if (diff = 0) then
|
||||
begin
|
||||
inc(pIn, STEPSIZE);
|
||||
inc(pMatch, STEPSIZE);
|
||||
continue;
|
||||
end;
|
||||
{$IFDEF WIN32}
|
||||
asm
|
||||
bsf eax, diff
|
||||
shr eax, 3
|
||||
mov incValue, eax
|
||||
end;
|
||||
{$ELSE}
|
||||
incValue := LZ4_NbCommonBytesx64(diff);
|
||||
// x64 mode does not allow asm inline
|
||||
{$ENDIF}
|
||||
inc(pIn, incValue);
|
||||
exit(cardinal(pIn - pStart));
|
||||
end;
|
||||
{$IFDEF WIN64}
|
||||
if (pIn < (pInLimit - 3)) and (pCardinal(pMatch)^ = pCardinal(pIn)^) then
|
||||
begin
|
||||
inc(pIn, 4);
|
||||
inc(pMatch, 4);
|
||||
end;
|
||||
{$ENDIF}
|
||||
if ((pIn < (pInLimit - 1)) and (pWord(pMatch)^ = pWord(pIn)^)) then
|
||||
begin
|
||||
inc(pIn, 2);
|
||||
inc(pMatch, 2);
|
||||
end;
|
||||
if ((pIn < pInLimit) and (pMatch^ = pIn^)) then
|
||||
inc(pIn);
|
||||
result := cardinal(pIn - pStart);
|
||||
end;
|
||||
|
||||
function LZ4_read16(const memPtr: pointer): word; inline;
|
||||
begin
|
||||
result := pWord(memPtr)^;
|
||||
end;
|
||||
|
||||
function LZ4_read64(const memPtr: pointer): uint64; inline;
|
||||
begin
|
||||
result := pUint64(memPtr)^;
|
||||
end;
|
||||
|
||||
{$IFDEF WILDCOPY_ASM}
|
||||
{$IFDEF WIN32}
|
||||
|
||||
procedure LZ4_wildCopy;
|
||||
// (dstPtr: pointer; const srcPtr: pointer; dstEnd: pointer);
|
||||
asm
|
||||
push edi
|
||||
push esi
|
||||
mov edi, eax
|
||||
mov esi, edx
|
||||
// copyCount := (((e - d) - 1) div 8) * 8 + 8;
|
||||
sub ecx, eax // (e - d)
|
||||
dec ecx // e - d) - 1)
|
||||
shr ecx, 3 // ((e - d) - 1) div 8)
|
||||
shl ecx, 3 // ((e - d) - 1) div 8) * 8
|
||||
add ecx, 8 // ((e - d) - 1) div 8) * 8 + 8
|
||||
|
||||
// if copyCount <= 0 then
|
||||
// copyCount := 8;
|
||||
mov eax, 8
|
||||
cmp ecx, 0
|
||||
cmovbe ecx, eax
|
||||
shr ecx, 2
|
||||
rep movsd
|
||||
pop esi
|
||||
pop edi
|
||||
end;
|
||||
|
||||
{$ELSE}
|
||||
|
||||
procedure LZ4_wildCopy;
|
||||
// (dstPtr: pointer; const srcPtr: pointer; dstEnd: pointer);
|
||||
asm
|
||||
mov r10, rdi
|
||||
mov r11, rsi
|
||||
mov rdi, rcx
|
||||
mov rsi, rdx
|
||||
// copyCount := (((e - d) - 1) div 8) * 8 + 8;
|
||||
sub r8, rcx // (dstEnd - dest)
|
||||
mov rax, 8
|
||||
dec r8 // e - d) - 1)
|
||||
shr r8, 3 // ((e - d) - 1) div 8)
|
||||
shl r8, 3 // ((e - d) - 1) div 8) * 8
|
||||
add r8, rax // ((e - d) - 1) div 8) * 8 + 8
|
||||
cmp r8, 0
|
||||
cmovbe r8, rax
|
||||
mov rcx, r8
|
||||
shr rcx, 3
|
||||
rep movsq
|
||||
mov rdi, r10
|
||||
mov rsi, r11
|
||||
end;
|
||||
{$ENDIF}
|
||||
{$ELSE}
|
||||
|
||||
procedure LZ4_wildCopy(dstPtr: pointer; const srcPtr: pointer;
|
||||
dstEnd: pointer); inline;
|
||||
var
|
||||
d: pByte;
|
||||
s: pByte;
|
||||
e: pByte;
|
||||
begin
|
||||
d := dstPtr;
|
||||
s := srcPtr;
|
||||
e := dstEnd;
|
||||
repeat
|
||||
{$IFDEF WIN32}
|
||||
// pCardinal(d)[0] := pCardinal(s)[0];
|
||||
// pCardinal(d)[1] := pCardinal(s)[1];
|
||||
pUint64(d)^ := pUint64(s)^;
|
||||
{$ELSE}
|
||||
pUint64(d)^ := pUint64(s)^;
|
||||
{$ENDIF}
|
||||
inc(d, 8);
|
||||
inc(s, 8);
|
||||
until not(d < e);
|
||||
end;
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
procedure LZ4_writeLE16(memPtr: pointer; value: word); inline;
|
||||
begin
|
||||
pWord(memPtr)^ := value;
|
||||
|
||||
end;
|
||||
|
||||
function LZ4_decompress_generic(const source: pointer; const dest: pointer;
|
||||
inputSize: integer; outputSize: integer; endOnInput: integer;
|
||||
partialDecoding: integer; targetOutputSize: integer; dict: integer;
|
||||
const lowPrefix: pByte; const dictStart: pByte;
|
||||
const dictSize: size_t): integer;
|
||||
var
|
||||
ip: pByte;
|
||||
iend: pByte;
|
||||
op: pByte;
|
||||
oend: pByte;
|
||||
cpy: pByte;
|
||||
oexit: pByte;
|
||||
lowLimit: pByte;
|
||||
dictEnd: pByte;
|
||||
safeDecode: Boolean;
|
||||
checkOffset: Boolean;
|
||||
token: cardinal;
|
||||
length: size_t;
|
||||
match: pByte;
|
||||
s: cardinal;
|
||||
booleantest: Boolean;
|
||||
copySize: size_t;
|
||||
endOfMatch: pByte;
|
||||
copyFrom: pByte;
|
||||
dec64: size_t;
|
||||
const
|
||||
dec32table: array [0 .. 7] of size_t = (4, 1, 2, 1, 4, 4, 4, 4);
|
||||
dec64table: array [0 .. 7] of size_t = (0, 0, 0, size_t(-1), 0, 1, 2, 3);
|
||||
label
|
||||
_output_error;
|
||||
begin
|
||||
ip := pByte(source);
|
||||
iend := ip + inputSize;
|
||||
op := pByte(dest);
|
||||
oend := op + outputSize;
|
||||
oexit := op + targetOutputSize;
|
||||
lowLimit := lowPrefix - dictSize;
|
||||
dictEnd := pByte(dictStart) + dictSize;
|
||||
safeDecode := (endOnInput = integer(endOnInputSize));
|
||||
checkOffset := ((safeDecode) and (dictSize < 65536));
|
||||
|
||||
if (partialDecoding <> 0) and (oexit > oend - _MFLIMIT) then
|
||||
oexit := oend - _MFLIMIT;
|
||||
if (endOnInput <> 0) and (outputSize = 0) then
|
||||
begin
|
||||
if (inputSize = 1) and (ip^ = 0) then
|
||||
exit(0)
|
||||
else
|
||||
exit(-1);
|
||||
end;
|
||||
if (endOnInput = 0) and (outputSize = 0) then
|
||||
begin
|
||||
if ip^ = 0 then
|
||||
exit(1)
|
||||
else
|
||||
exit(-1);
|
||||
end;
|
||||
|
||||
while True do
|
||||
begin
|
||||
token := ip^;
|
||||
inc(ip);
|
||||
length := token shr ML_BITS;
|
||||
if length = RUN_MASK then
|
||||
begin
|
||||
while True do
|
||||
begin
|
||||
s := ip^;
|
||||
inc(ip);
|
||||
inc(length, s);
|
||||
if endOnInput <> 0 then
|
||||
begin
|
||||
if not(ip < iend - RUN_MASK) then
|
||||
break;
|
||||
end;
|
||||
if s <> 255 then
|
||||
break;
|
||||
end;
|
||||
if safeDecode and (size_t(op + length) < size_t(op)) then
|
||||
goto _output_error;
|
||||
if safeDecode and (size_t(ip + length) < size_t(ip)) then
|
||||
goto _output_error;
|
||||
end;
|
||||
cpy := op + length;
|
||||
if partialDecoding <> 0 then
|
||||
booleantest := cpy > oexit
|
||||
else
|
||||
booleantest := cpy > oend - _MFLIMIT;
|
||||
|
||||
if ((endOnInput <> 0) and ((booleantest) or
|
||||
(ip + length > iend - (2 + 1 + LASTLITERALS)))) or
|
||||
((endOnInput = 0) and (cpy > oend - COPYLENGTH)) then
|
||||
begin
|
||||
if partialDecoding <> 0 then
|
||||
begin
|
||||
if (cpy > oend) then
|
||||
goto _output_error;
|
||||
if ((endOnInput <> 0) and (ip + length > iend)) then
|
||||
goto _output_error;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if ((endOnInput = 0) and (cpy <> oend)) then
|
||||
goto _output_error;
|
||||
if ((endOnInput <> 0) and ((ip + length <> iend) or (cpy > oend))) then
|
||||
goto _output_error;
|
||||
end;
|
||||
move(ip^, op^, length);
|
||||
inc(ip, length);
|
||||
inc(op, length);
|
||||
break;
|
||||
end;
|
||||
LZ4_wildCopy(op, ip, cpy);
|
||||
inc(ip, length);
|
||||
op := cpy;
|
||||
match := cpy - LZ4_read16(ip); // LZ4_readLE16 = LZ4_read16 for unaligned
|
||||
inc(ip, 2);
|
||||
|
||||
if checkOffset and (match < lowLimit) then
|
||||
goto _output_error;
|
||||
|
||||
length := token and ML_MASK;
|
||||
if length = ML_MASK then
|
||||
begin
|
||||
while True do
|
||||
begin
|
||||
if ((endOnInput <> 0) and (ip > iend - LASTLITERALS)) then
|
||||
goto _output_error;
|
||||
s := ip^;
|
||||
inc(ip);
|
||||
inc(length, s);
|
||||
if s <> 255 then
|
||||
break;
|
||||
end;
|
||||
if safeDecode and (size_t(op + length) < size_t(op)) then
|
||||
goto _output_error;
|
||||
end;
|
||||
inc(length, MINMATCH);
|
||||
if (dict = integer(usingExtDict)) and (match < lowPrefix) then
|
||||
begin
|
||||
if op + length > oend - LASTLITERALS then
|
||||
goto _output_error;
|
||||
if (length <= size_t(lowPrefix - match)) then
|
||||
begin
|
||||
match := dictEnd - (lowPrefix - match);
|
||||
move(match^, op^, length);
|
||||
inc(op, length);
|
||||
end
|
||||
else
|
||||
begin
|
||||
copySize := size_t(lowPrefix - match);
|
||||
move((dictEnd - copySize)^, op^, copySize);
|
||||
inc(op, copySize);
|
||||
copySize := length - copySize;
|
||||
if copySize > size_t(op - lowPrefix) then
|
||||
begin
|
||||
endOfMatch := op + copySize;
|
||||
copyFrom := lowPrefix;
|
||||
while (op < endOfMatch) do
|
||||
begin
|
||||
op^ := copyFrom^;
|
||||
inc(op);
|
||||
inc(copyFrom);
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
move(lowPrefix^, op^, copySize);
|
||||
inc(op, copySize);
|
||||
end;
|
||||
end;
|
||||
continue;
|
||||
end;
|
||||
cpy := op + length;
|
||||
if (op - match) < 8 then
|
||||
begin
|
||||
dec64 := dec64table[op - match];
|
||||
op[0] := match[0];
|
||||
op[1] := match[1];
|
||||
op[2] := match[2];
|
||||
op[3] := match[3];
|
||||
inc(match, dec32table[op - match]);
|
||||
pCardinal(op + 4)^ := pCardinal(match)^;
|
||||
inc(op, 8);
|
||||
dec(match, dec64);
|
||||
end
|
||||
else
|
||||
begin
|
||||
{$IFDEF WIN64}
|
||||
pUint64(op)^ := pUint64(match)^;
|
||||
{$ELSE}
|
||||
pCardinal(op)[0] := pCardinal(match)[0];
|
||||
pCardinal(op)[1] := pCardinal(match)[1];
|
||||
{$ENDIF}
|
||||
inc(op, 8);
|
||||
inc(match, 8);
|
||||
end;
|
||||
|
||||
if cpy > oend - 12 then
|
||||
begin
|
||||
if (cpy > oend - LASTLITERALS) then
|
||||
goto _output_error;
|
||||
if (op < oend - 8) then
|
||||
begin
|
||||
LZ4_wildCopy(op, match, oend - 8);
|
||||
inc(match, (oend - 8) - op);
|
||||
op := oend - 8;
|
||||
end;
|
||||
while (op < cpy) do
|
||||
begin
|
||||
op^ := match^;
|
||||
inc(op);
|
||||
inc(match);
|
||||
end;
|
||||
end
|
||||
else
|
||||
LZ4_wildCopy(op, match, cpy);
|
||||
op := cpy;
|
||||
end;
|
||||
if (endOnInput <> 0) then
|
||||
result := integer(op - pByte(dest))
|
||||
else
|
||||
result := integer(ip - pByte(source));
|
||||
exit;
|
||||
_output_error:
|
||||
result := -(ip - pByte(source)) - 1;
|
||||
end;
|
||||
|
||||
end.
|
Reference in New Issue
Block a user