chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: LGPL-2.1-or-later
This commit is contained in:
@@ -0,0 +1,619 @@
|
||||
// LzmsDecoder.cpp
|
||||
// The code is based on LZMS description from wimlib code
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "LzmsDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzms {
|
||||
|
||||
class CBitDecoder
|
||||
{
|
||||
public:
|
||||
const Byte *_buf;
|
||||
unsigned _bitPos;
|
||||
|
||||
void Init(const Byte *buf, size_t size) throw()
|
||||
{
|
||||
_buf = buf + size;
|
||||
_bitPos = 0;
|
||||
}
|
||||
|
||||
Z7_FORCE_INLINE
|
||||
UInt32 GetValue(unsigned numBits) const
|
||||
{
|
||||
UInt32 v =
|
||||
((UInt32)_buf[-1] << 16) |
|
||||
((UInt32)_buf[-2] << 8) |
|
||||
(UInt32)_buf[-3];
|
||||
v >>= 24 - numBits - _bitPos;
|
||||
return v & ((1u << numBits) - 1);
|
||||
}
|
||||
|
||||
Z7_FORCE_INLINE
|
||||
UInt32 GetValue_InHigh32bits()
|
||||
{
|
||||
return GetUi32(_buf - 4) << _bitPos;
|
||||
}
|
||||
|
||||
void MovePos(unsigned numBits)
|
||||
{
|
||||
_bitPos += numBits;
|
||||
_buf -= (_bitPos >> 3);
|
||||
_bitPos &= 7;
|
||||
}
|
||||
|
||||
UInt32 ReadBits32(unsigned numBits)
|
||||
{
|
||||
UInt32 mask = (((UInt32)1 << numBits) - 1);
|
||||
numBits += _bitPos;
|
||||
const Byte *buf = _buf;
|
||||
UInt32 v = GetUi32(buf - 4);
|
||||
if (numBits > 32)
|
||||
{
|
||||
v <<= (numBits - 32);
|
||||
v |= (UInt32)buf[-5] >> (40 - numBits);
|
||||
}
|
||||
else
|
||||
v >>= (32 - numBits);
|
||||
_buf = buf - (numBits >> 3);
|
||||
_bitPos = numBits & 7;
|
||||
return v & mask;
|
||||
}
|
||||
};
|
||||
|
||||
static UInt32 g_PosBases[k_NumPosSyms /* + 1 */];
|
||||
|
||||
static Byte g_PosDirectBits[k_NumPosSyms];
|
||||
|
||||
static const Byte k_PosRuns[31] =
|
||||
{
|
||||
8, 0, 9, 7, 10, 15, 15, 20, 20, 30, 33, 40, 42, 45, 60, 73,
|
||||
80, 85, 95, 105, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
|
||||
};
|
||||
|
||||
static UInt32 g_LenBases[k_NumLenSyms];
|
||||
|
||||
static const Byte k_LenDirectBits[k_NumLenSyms] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
|
||||
2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6,
|
||||
7, 8, 9, 10, 16, 30,
|
||||
};
|
||||
|
||||
static struct CInit
|
||||
{
|
||||
CInit()
|
||||
{
|
||||
{
|
||||
unsigned sum = 0;
|
||||
for (unsigned i = 0; i < sizeof(k_PosRuns); i++)
|
||||
{
|
||||
unsigned t = k_PosRuns[i];
|
||||
for (unsigned y = 0; y < t; y++)
|
||||
g_PosDirectBits[sum + y] = (Byte)i;
|
||||
sum += t;
|
||||
}
|
||||
}
|
||||
{
|
||||
UInt32 sum = 1;
|
||||
for (unsigned i = 0; i < k_NumPosSyms; i++)
|
||||
{
|
||||
g_PosBases[i] = sum;
|
||||
sum += (UInt32)1 << g_PosDirectBits[i];
|
||||
}
|
||||
// g_PosBases[k_NumPosSyms] = sum;
|
||||
}
|
||||
{
|
||||
UInt32 sum = 1;
|
||||
for (unsigned i = 0; i < k_NumLenSyms; i++)
|
||||
{
|
||||
g_LenBases[i] = sum;
|
||||
sum += (UInt32)1 << k_LenDirectBits[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} g_Init;
|
||||
|
||||
static unsigned GetNumPosSlots(size_t size)
|
||||
{
|
||||
if (size < 2)
|
||||
return 0;
|
||||
|
||||
size--;
|
||||
|
||||
if (size >= g_PosBases[k_NumPosSyms - 1])
|
||||
return k_NumPosSyms;
|
||||
unsigned left = 0;
|
||||
unsigned right = k_NumPosSyms;
|
||||
for (;;)
|
||||
{
|
||||
const unsigned m = (left + right) / 2;
|
||||
if (left == m)
|
||||
return m + 1;
|
||||
if (size >= g_PosBases[m])
|
||||
left = m;
|
||||
else
|
||||
right = m;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const Int32 k_x86_WindowSize = 65535;
|
||||
static const Int32 k_x86_TransOffset = 1023;
|
||||
|
||||
static const size_t k_x86_HistorySize = 1 << 16;
|
||||
|
||||
static void x86_Filter(Byte *data, UInt32 size, Int32 *history)
|
||||
{
|
||||
if (size <= 17)
|
||||
return;
|
||||
|
||||
Byte isCode[256];
|
||||
memset(isCode, 0, 256);
|
||||
isCode[0x48] = 1;
|
||||
isCode[0x4C] = 1;
|
||||
isCode[0xE8] = 1;
|
||||
isCode[0xE9] = 1;
|
||||
isCode[0xF0] = 1;
|
||||
isCode[0xFF] = 1;
|
||||
|
||||
{
|
||||
for (size_t i = 0; i < k_x86_HistorySize; i++)
|
||||
history[i] = -(Int32)k_x86_WindowSize - 1;
|
||||
}
|
||||
|
||||
size -= 16;
|
||||
const unsigned kSave = 6;
|
||||
const Byte savedByte = data[(size_t)size + kSave];
|
||||
data[(size_t)size + kSave] = 0xE8;
|
||||
Int32 last_x86_pos = -k_x86_TransOffset - 1;
|
||||
|
||||
// first byte is ignored
|
||||
Int32 i = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
Byte *p = data + (UInt32)i;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (isCode[*(++p)]) break;
|
||||
if (isCode[*(++p)]) break;
|
||||
}
|
||||
|
||||
i = (Int32)(p - data);
|
||||
if ((UInt32)i >= size)
|
||||
break;
|
||||
|
||||
UInt32 codeLen;
|
||||
|
||||
Int32 maxTransOffset = k_x86_TransOffset;
|
||||
|
||||
const Byte b = p[0];
|
||||
|
||||
if ((b & 0x80) == 0) // REX (0x48 or 0x4c)
|
||||
{
|
||||
const unsigned b2 = p[2] - 0x5; // [RIP + disp32]
|
||||
if (b2 & 0x7)
|
||||
continue;
|
||||
if (p[1] != 0x8d) // LEA
|
||||
{
|
||||
if (p[1] != 0x8b || b != 0x48 || (b2 & 0xf7))
|
||||
continue;
|
||||
// MOV RAX / RCX, [RIP + disp32]
|
||||
}
|
||||
codeLen = 3;
|
||||
}
|
||||
else if (b == 0xE8)
|
||||
{
|
||||
// CALL
|
||||
codeLen = 1;
|
||||
maxTransOffset /= 2;
|
||||
}
|
||||
else if (b == 0xE9)
|
||||
{
|
||||
// JUMP
|
||||
i += 4;
|
||||
continue;
|
||||
}
|
||||
else if (b == 0xF0)
|
||||
{
|
||||
if (p[1] != 0x83 || p[2] != 0x05)
|
||||
continue;
|
||||
// LOCK ADD [RIP + disp32], imm8
|
||||
// LOCK ADD [disp32], imm8
|
||||
codeLen = 3;
|
||||
}
|
||||
else
|
||||
// if (b == 0xFF)
|
||||
{
|
||||
if (p[1] != 0x15)
|
||||
continue;
|
||||
// CALL [RIP + disp32];
|
||||
// CALL [disp32];
|
||||
codeLen = 2;
|
||||
}
|
||||
|
||||
Int32 *target;
|
||||
{
|
||||
Byte *p2 = p + codeLen;
|
||||
UInt32 n = GetUi32(p2);
|
||||
if (i - last_x86_pos <= maxTransOffset)
|
||||
{
|
||||
n = (UInt32)((Int32)n - i);
|
||||
SetUi32(p2, n)
|
||||
}
|
||||
target = history + (((UInt32)i + n) & 0xFFFF);
|
||||
}
|
||||
|
||||
i += (Int32)(codeLen + sizeof(UInt32) - 1);
|
||||
|
||||
if (i - *target <= k_x86_WindowSize)
|
||||
last_x86_pos = i;
|
||||
*target = i;
|
||||
}
|
||||
|
||||
data[(size_t)size + kSave] = savedByte;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// static const int kLenIdNeedInit = -2;
|
||||
|
||||
CDecoder::CDecoder():
|
||||
_x86_history(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
::MidFree(_x86_history);
|
||||
}
|
||||
|
||||
// #define RIF(x) { if (!(x)) return false; }
|
||||
|
||||
#define LIMIT_CHECK if (_bs._buf < _rc.cur) return S_FALSE;
|
||||
// #define LIMIT_CHECK
|
||||
|
||||
#define READ_BITS_CHECK(numDirectBits) \
|
||||
if (_bs._buf < _rc.cur) return S_FALSE; \
|
||||
if ((size_t)(_bs._buf - _rc.cur) < (numDirectBits >> 3)) return S_FALSE;
|
||||
|
||||
|
||||
#define HUFF_DEC(sym, pp) \
|
||||
sym = pp.DecodeFull(&_bs); \
|
||||
pp.Freqs[sym]++; \
|
||||
if (--pp.RebuildRem == 0) pp.Rebuild();
|
||||
|
||||
|
||||
HRESULT CDecoder::CodeReal(const Byte *in, size_t inSize, Byte *_win, size_t outSize)
|
||||
{
|
||||
// size_t inSizeT = (size_t)(inSize);
|
||||
// Byte *_win;
|
||||
// size_t _pos;
|
||||
_pos = 0;
|
||||
|
||||
CBitDecoder _bs;
|
||||
CRangeDecoder _rc;
|
||||
|
||||
if (inSize < 8 || (inSize & 1) != 0)
|
||||
return S_FALSE;
|
||||
_rc.Init(in, inSize);
|
||||
if (_rc.code >= _rc.range)
|
||||
return S_FALSE;
|
||||
_bs.Init(in, inSize);
|
||||
|
||||
{
|
||||
{
|
||||
{
|
||||
for (unsigned i = 0 ; i < k_NumReps + 1; i++)
|
||||
_reps[i] = i + 1;
|
||||
}
|
||||
|
||||
{
|
||||
for (unsigned i = 0 ; i < k_NumReps + 1; i++)
|
||||
_deltaReps[i] = i + 1;
|
||||
}
|
||||
|
||||
mainState = 0;
|
||||
matchState = 0;
|
||||
|
||||
{ for (size_t i = 0; i < k_NumMainProbs; i++) mainProbs[i].Init(); }
|
||||
{ for (size_t i = 0; i < k_NumMatchProbs; i++) matchProbs[i].Init(); }
|
||||
|
||||
{
|
||||
for (size_t k = 0; k < k_NumReps; k++)
|
||||
{
|
||||
lzRepStates[k] = 0;
|
||||
for (size_t i = 0; i < k_NumRepProbs; i++)
|
||||
lzRepProbs[k][i].Init();
|
||||
}
|
||||
}
|
||||
{
|
||||
for (size_t k = 0; k < k_NumReps; k++)
|
||||
{
|
||||
deltaRepStates[k] = 0;
|
||||
for (size_t i = 0; i < k_NumRepProbs; i++)
|
||||
deltaRepProbs[k][i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
m_LitDecoder.Init();
|
||||
m_LenDecoder.Init();
|
||||
m_PowerDecoder.Init();
|
||||
unsigned numPosSyms = GetNumPosSlots(outSize);
|
||||
if (numPosSyms < 2)
|
||||
numPosSyms = 2;
|
||||
m_PosDecoder.Init(numPosSyms);
|
||||
m_DeltaDecoder.Init(numPosSyms);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
unsigned prevType = 0;
|
||||
|
||||
while (_pos < outSize)
|
||||
{
|
||||
if (_rc.Decode(&mainState, k_NumMainProbs, mainProbs) == 0)
|
||||
{
|
||||
unsigned number;
|
||||
HUFF_DEC(number, m_LitDecoder)
|
||||
LIMIT_CHECK
|
||||
_win[_pos++] = (Byte)number;
|
||||
prevType = 0;
|
||||
}
|
||||
else if (_rc.Decode(&matchState, k_NumMatchProbs, matchProbs) == 0)
|
||||
{
|
||||
UInt32 distance;
|
||||
|
||||
if (_rc.Decode(&lzRepStates[0], k_NumRepProbs, lzRepProbs[0]) == 0)
|
||||
{
|
||||
unsigned number;
|
||||
HUFF_DEC(number, m_PosDecoder)
|
||||
LIMIT_CHECK
|
||||
|
||||
const unsigned numDirectBits = g_PosDirectBits[number];
|
||||
distance = g_PosBases[number];
|
||||
READ_BITS_CHECK(numDirectBits)
|
||||
distance += _bs.ReadBits32(numDirectBits);
|
||||
// LIMIT_CHECK
|
||||
_reps[3] = _reps[2];
|
||||
_reps[2] = _reps[1];
|
||||
_reps[1] = _reps[0];
|
||||
_reps[0] = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_rc.Decode(&lzRepStates[1], k_NumRepProbs, lzRepProbs[1]) == 0)
|
||||
{
|
||||
if (prevType != 1)
|
||||
distance = _reps[0];
|
||||
else
|
||||
{
|
||||
distance = _reps[1];
|
||||
_reps[1] = _reps[0];
|
||||
_reps[0] = distance;
|
||||
}
|
||||
}
|
||||
else if (_rc.Decode(&lzRepStates[2], k_NumRepProbs, lzRepProbs[2]) == 0)
|
||||
{
|
||||
if (prevType != 1)
|
||||
{
|
||||
distance = _reps[1];
|
||||
_reps[1] = _reps[0];
|
||||
_reps[0] = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = _reps[2];
|
||||
_reps[2] = _reps[1];
|
||||
_reps[1] = _reps[0];
|
||||
_reps[0] = distance;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prevType != 1)
|
||||
{
|
||||
distance = _reps[2];
|
||||
_reps[2] = _reps[1];
|
||||
_reps[1] = _reps[0];
|
||||
_reps[0] = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = _reps[3];
|
||||
_reps[3] = _reps[2];
|
||||
_reps[2] = _reps[1];
|
||||
_reps[1] = _reps[0];
|
||||
_reps[0] = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned lenSlot;
|
||||
HUFF_DEC(lenSlot, m_LenDecoder)
|
||||
LIMIT_CHECK
|
||||
|
||||
UInt32 len = g_LenBases[lenSlot];
|
||||
{
|
||||
const unsigned numDirectBits = k_LenDirectBits[lenSlot];
|
||||
READ_BITS_CHECK(numDirectBits)
|
||||
len += _bs.ReadBits32(numDirectBits);
|
||||
}
|
||||
// LIMIT_CHECK
|
||||
|
||||
if (len > outSize - _pos)
|
||||
return S_FALSE;
|
||||
|
||||
if (distance > _pos)
|
||||
return S_FALSE;
|
||||
|
||||
Byte *dest = _win + _pos;
|
||||
const Byte *src = dest - distance;
|
||||
_pos += len;
|
||||
do
|
||||
*dest++ = *src++;
|
||||
while (--len);
|
||||
|
||||
prevType = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt64 distance;
|
||||
|
||||
unsigned power;
|
||||
UInt32 distance32;
|
||||
|
||||
if (_rc.Decode(&deltaRepStates[0], k_NumRepProbs, deltaRepProbs[0]) == 0)
|
||||
{
|
||||
HUFF_DEC(power, m_PowerDecoder)
|
||||
LIMIT_CHECK
|
||||
|
||||
unsigned number;
|
||||
HUFF_DEC(number, m_DeltaDecoder)
|
||||
LIMIT_CHECK
|
||||
|
||||
const unsigned numDirectBits = g_PosDirectBits[number];
|
||||
distance32 = g_PosBases[number];
|
||||
READ_BITS_CHECK(numDirectBits)
|
||||
distance32 += _bs.ReadBits32(numDirectBits);
|
||||
// LIMIT_CHECK
|
||||
|
||||
distance = ((UInt64)power << 32) | distance32;
|
||||
|
||||
_deltaReps[3] = _deltaReps[2];
|
||||
_deltaReps[2] = _deltaReps[1];
|
||||
_deltaReps[1] = _deltaReps[0];
|
||||
_deltaReps[0] = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_rc.Decode(&deltaRepStates[1], k_NumRepProbs, deltaRepProbs[1]) == 0)
|
||||
{
|
||||
if (prevType != 2)
|
||||
distance = _deltaReps[0];
|
||||
else
|
||||
{
|
||||
distance = _deltaReps[1];
|
||||
_deltaReps[1] = _deltaReps[0];
|
||||
_deltaReps[0] = distance;
|
||||
}
|
||||
}
|
||||
else if (_rc.Decode(&deltaRepStates[2], k_NumRepProbs, deltaRepProbs[2]) == 0)
|
||||
{
|
||||
if (prevType != 2)
|
||||
{
|
||||
distance = _deltaReps[1];
|
||||
_deltaReps[1] = _deltaReps[0];
|
||||
_deltaReps[0] = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = _deltaReps[2];
|
||||
_deltaReps[2] = _deltaReps[1];
|
||||
_deltaReps[1] = _deltaReps[0];
|
||||
_deltaReps[0] = distance;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prevType != 2)
|
||||
{
|
||||
distance = _deltaReps[2];
|
||||
_deltaReps[2] = _deltaReps[1];
|
||||
_deltaReps[1] = _deltaReps[0];
|
||||
_deltaReps[0] = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = _deltaReps[3];
|
||||
_deltaReps[3] = _deltaReps[2];
|
||||
_deltaReps[2] = _deltaReps[1];
|
||||
_deltaReps[1] = _deltaReps[0];
|
||||
_deltaReps[0] = distance;
|
||||
}
|
||||
}
|
||||
distance32 = (UInt32)_deltaReps[0] & 0xFFFFFFFF;
|
||||
power = (UInt32)(_deltaReps[0] >> 32);
|
||||
}
|
||||
|
||||
const UInt32 dist = (distance32 << power);
|
||||
|
||||
unsigned lenSlot;
|
||||
HUFF_DEC(lenSlot, m_LenDecoder)
|
||||
LIMIT_CHECK
|
||||
|
||||
UInt32 len = g_LenBases[lenSlot];
|
||||
{
|
||||
const unsigned numDirectBits = k_LenDirectBits[lenSlot];
|
||||
READ_BITS_CHECK(numDirectBits)
|
||||
len += _bs.ReadBits32(numDirectBits);
|
||||
}
|
||||
// LIMIT_CHECK
|
||||
|
||||
if (len > outSize - _pos)
|
||||
return S_FALSE;
|
||||
|
||||
size_t span = (size_t)1 << power;
|
||||
if ((UInt64)dist + span > _pos)
|
||||
return S_FALSE;
|
||||
Byte *dest = _win + _pos - span;
|
||||
const Byte *src = dest - dist;
|
||||
_pos += len;
|
||||
do
|
||||
{
|
||||
*(dest + span) = (Byte)(*(dest) + *(src + span) - *(src));
|
||||
src++;
|
||||
dest++;
|
||||
}
|
||||
while (--len);
|
||||
|
||||
prevType = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_rc.Normalize();
|
||||
if (_rc.code != 0)
|
||||
return S_FALSE;
|
||||
if (_rc.cur > _bs._buf
|
||||
|| (_rc.cur == _bs._buf && _bs._bitPos != 0))
|
||||
return S_FALSE;
|
||||
|
||||
/*
|
||||
int delta = (int)(_bs._buf - _rc.cur);
|
||||
if (_bs._bitPos != 0)
|
||||
delta--;
|
||||
if ((delta & 1))
|
||||
delta--;
|
||||
printf("%d ", delta);
|
||||
*/
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::Code(const Byte *in, size_t inSize, Byte *out, size_t outSize)
|
||||
{
|
||||
if (!_x86_history)
|
||||
{
|
||||
_x86_history = (Int32 *)::MidAlloc(sizeof(Int32) * k_x86_HistorySize);
|
||||
if (!_x86_history)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
HRESULT res;
|
||||
// try
|
||||
{
|
||||
res = CodeReal(in, inSize, out, outSize);
|
||||
}
|
||||
// catch (...) { res = S_FALSE; }
|
||||
x86_Filter(out, (UInt32)_pos, _x86_history);
|
||||
return res;
|
||||
}
|
||||
|
||||
}}
|
||||
Reference in New Issue
Block a user