This commit is contained in:
Igor Pavlov
2015-09-22 00:00:00 +00:00
committed by Kornel Lesiński
parent cba375916f
commit f6444c3256
96 changed files with 7301 additions and 2409 deletions

View File

@@ -173,7 +173,7 @@ HRESULT CBase::ReadBlock(UInt32 *charCounters, UInt32 blockSizeMax, CBlockProps
}
for (; i < kMaxAlphaSize; i++)
lens[i] = 0;
if (!m_HuffmanDecoders[t].SetCodeLengths(lens))
if (!m_HuffmanDecoders[t].Build(lens))
return S_FALSE;
}
while (++t < numTables);
@@ -205,7 +205,7 @@ HRESULT CBase::ReadBlock(UInt32 *charCounters, UInt32 blockSizeMax, CBlockProps
if (BitDecoder.ExtraBitsWereRead_Fast())
break;
UInt32 nextSym = huffmanDecoder->DecodeSymbol(&BitDecoder);
UInt32 nextSym = huffmanDecoder->Decode(&BitDecoder);
if (nextSym < 2)
{

View File

@@ -26,39 +26,51 @@ Byte CCoder::ReadAlignedByte()
return m_InBitStream.ReadAlignedByte();
}
bool CCoder::DeCodeLevelTable(Byte *values, unsigned numSymbols)
bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols)
{
unsigned i = 0;
do
{
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
if (number < kTableDirectLevels)
values[i++] = (Byte)number;
else if (number < kLevelTableSize)
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
if (sym < kTableDirectLevels)
levels[i++] = (Byte)sym;
else
{
if (number == kTableLevelRepNumber)
if (sym >= kLevelTableSize)
return false;
unsigned num;
unsigned numBits;
Byte symbol;
if (sym == kTableLevelRepNumber)
{
if (i == 0)
return false;
unsigned num = ReadBits(2) + 3;
for (; num > 0 && i < numSymbols; num--, i++)
values[i] = values[i - 1];
numBits = 2;
num = 0;
symbol = levels[i - 1];
}
else
{
unsigned num;
if (number == kTableLevel0Number)
num = ReadBits(3) + 3;
else
num = ReadBits(7) + 11;
for (; num > 0 && i < numSymbols; num--)
values[i++] = 0;
sym -= kTableLevel0Number;
sym <<= 2;
numBits = 3 + (unsigned)sym;
num = ((unsigned)sym << 1);
symbol = 0;
}
num += i + 3 + ReadBits(numBits);
if (num > numSymbols)
return false;
do
levels[i++] = symbol;
while (i < num);
}
else
return false;
}
while (i < numSymbols);
return true;
}
@@ -116,10 +128,10 @@ bool CCoder::ReadTables(void)
if (m_InBitStream.ExtraBitsWereRead())
return false;
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
RIF(m_LevelDecoder.Build(levelLevels));
Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
if (!DeCodeLevelTable(tmpLevels, numLitLenLevels + _numDistLevels))
if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels))
return false;
if (m_InBitStream.ExtraBitsWereRead())
@@ -129,8 +141,8 @@ bool CCoder::ReadTables(void)
memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
}
RIF(m_MainDecoder.SetCodeLengths(levels.litLenLevels));
return m_DistDecoder.SetCodeLengths(levels.distLevels);
RIF(m_MainDecoder.Build(levels.litLenLevels));
return m_DistDecoder.Build(levels.distLevels);
}
HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
@@ -161,6 +173,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
{
if (m_InBitStream.ExtraBitsWereRead())
return S_FALSE;
if (_needReadTable)
{
if (m_FinalBlock)
@@ -194,43 +207,44 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
if (m_InBitStream.ExtraBitsWereRead_Fast())
return S_FALSE;
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
if (number < 0x100)
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
if (sym < 0x100)
{
m_OutWindowStream.PutByte((Byte)number);
m_OutWindowStream.PutByte((Byte)sym);
curSize--;
continue;
}
else if (number == kSymbolEndOfBlock)
else if (sym == kSymbolEndOfBlock)
{
_needReadTable = true;
break;
}
else if (number < kMainTableSize)
else if (sym < kMainTableSize)
{
number -= kSymbolMatch;
sym -= kSymbolMatch;
UInt32 len;
{
unsigned numBits;
if (_deflate64Mode)
{
len = kLenStart64[number];
numBits = kLenDirectBits64[number];
len = kLenStart64[sym];
numBits = kLenDirectBits64[sym];
}
else
{
len = kLenStart32[number];
numBits = kLenDirectBits32[number];
len = kLenStart32[sym];
numBits = kLenDirectBits32[sym];
}
len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
}
UInt32 locLen = len;
if (locLen > curSize)
locLen = (UInt32)curSize;
number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
if (number >= _numDistLevels)
sym = m_DistDecoder.Decode(&m_InBitStream);
if (sym >= _numDistLevels)
return S_FALSE;
UInt32 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
UInt32 distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
if (!m_OutWindowStream.CopyBlock(distance, locLen))
return S_FALSE;
curSize -= locLen;
@@ -248,7 +262,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
if (finishInputStream && curSize == 0)
{
if (m_MainDecoder.DecodeSymbol(&m_InBitStream) != kSymbolEndOfBlock)
if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock)
return S_FALSE;
_needReadTable = true;
}
@@ -260,6 +274,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
return S_OK;
}
#ifdef _NO_EXCEPTIONS
#define DEFLATE_TRY_BEGIN
@@ -275,6 +290,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
#endif
HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
const UInt64 *outSize, ICompressProgressInfo *progress)
{
@@ -285,6 +301,7 @@ HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
const UInt64 start = m_OutWindowStream.GetProcessedSize();
for (;;)
{
UInt32 curSize = 1 << 18;
@@ -311,12 +328,14 @@ HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
}
}
if (_remainLen == kLenIdFinished && ZlibMode)
{
m_InBitStream.AlignToByte();
for (unsigned i = 0; i < 4; i++)
ZlibFooter[i] = ReadAlignedByte();
}
flusher.NeedFlush = false;
res = Flush();
if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError())
@@ -337,7 +356,7 @@ HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStr
STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
{
if (value == NULL)
if (!value)
return E_INVALIDARG;
*value = m_InBitStream.GetProcessedSize();
return S_OK;

View File

@@ -36,7 +36,7 @@ class CCoder:
NBitl::CDecoder<CInBuffer> m_InBitStream;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedMainTableSize> m_MainDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedDistTableSize> m_DistDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
NCompress::NHuffman::CDecoder7b<kLevelTableSize> m_LevelDecoder;
UInt32 m_StoredBlockSize;
@@ -56,7 +56,7 @@ class CCoder:
UInt32 ReadBits(unsigned numBits);
bool DeCodeLevelTable(Byte *values, unsigned numSymbols);
bool DecodeLevels(Byte *levels, unsigned numSymbols);
bool ReadTables();
HRESULT Flush() { return m_OutWindowStream.Flush(); }

View File

@@ -8,42 +8,33 @@
namespace NCompress {
namespace NHuffman {
const unsigned kNumTableBits = 9;
template <unsigned kNumBitsMax, UInt32 m_NumSymbols>
template <unsigned kNumBitsMax, UInt32 m_NumSymbols, unsigned kNumTableBits = 9>
class CDecoder
{
UInt32 m_Limits[kNumBitsMax + 1]; // m_Limits[i] = value limit for symbols with length = i
UInt32 m_Positions[kNumBitsMax + 1]; // m_Positions[i] = index in m_Symbols[] of first symbol with length = i
UInt32 m_Symbols[m_NumSymbols];
Byte m_Lengths[1 << kNumTableBits]; // Table of length for short codes
UInt32 _limits[kNumBitsMax + 2];
UInt32 _poses[kNumBitsMax + 1];
UInt16 _lens[1 << kNumTableBits];
UInt16 _symbols[m_NumSymbols];
public:
bool SetCodeLengths(const Byte *lens)
bool Build(const Byte *lens) throw()
{
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPositions[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
unsigned i;
for (i = 1; i <= kNumBitsMax; i++)
for (i = 0; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
UInt32 symbol;
UInt32 sym;
for (symbol = 0; symbol < m_NumSymbols; symbol++)
{
unsigned len = lens[symbol];
if (len > kNumBitsMax)
return false;
lenCounts[len]++;
m_Symbols[symbol] = 0xFFFFFFFF;
}
for (sym = 0; sym < m_NumSymbols; sym++)
lenCounts[lens[sym]]++;
lenCounts[0] = 0;
m_Positions[0] = m_Limits[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
UInt32 index = 0;
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
for (i = 1; i <= kNumBitsMax; i++)
@@ -51,44 +42,216 @@ public:
startPos += lenCounts[i] << (kNumBitsMax - i);
if (startPos > kMaxValue)
return false;
m_Limits[i] = (i == kNumBitsMax) ? kMaxValue : startPos;
m_Positions[i] = m_Positions[i - 1] + lenCounts[i - 1];
tmpPositions[i] = m_Positions[i];
if (i <= kNumTableBits)
_limits[i] = startPos;
_poses[i] = _poses[i - 1] + lenCounts[i - 1];
tmpPoses[i] = _poses[i];
}
_limits[kNumBitsMax + 1] = kMaxValue;
for (sym = 0; sym < m_NumSymbols; sym++)
{
unsigned len = lens[sym];
if (len == 0)
continue;
unsigned offset = tmpPoses[len];
_symbols[offset] = (UInt16)sym;
tmpPoses[len] = offset + 1;
if (len <= kNumTableBits)
{
UInt32 limit = (m_Limits[i] >> (kNumBitsMax - kNumTableBits));
for (; index < limit; index++)
m_Lengths[index] = (Byte)i;
offset -= _poses[len];
UInt32 num = (UInt32)1 << (kNumTableBits - len);
UInt16 val = (UInt16)((sym << 4) | len);
UInt16 *dest = _lens + (_limits[len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
for (UInt32 k = 0; k < num; k++)
dest[k] = val;
}
}
for (symbol = 0; symbol < m_NumSymbols; symbol++)
return true;
}
bool BuildFull(const Byte *lens, UInt32 numSymbols = m_NumSymbols) throw()
{
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
unsigned i;
for (i = 0; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
UInt32 sym;
for (sym = 0; sym < numSymbols; sym++)
lenCounts[lens[sym]]++;
lenCounts[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
for (i = 1; i <= kNumBitsMax; i++)
{
unsigned len = lens[symbol];
if (len != 0)
m_Symbols[tmpPositions[len]++] = symbol;
startPos += lenCounts[i] << (kNumBitsMax - i);
if (startPos > kMaxValue)
return false;
_limits[i] = startPos;
_poses[i] = _poses[i - 1] + lenCounts[i - 1];
tmpPoses[i] = _poses[i];
}
_limits[kNumBitsMax + 1] = kMaxValue;
for (sym = 0; sym < numSymbols; sym++)
{
unsigned len = lens[sym];
if (len == 0)
continue;
unsigned offset = tmpPoses[len];
_symbols[offset] = (UInt16)sym;
tmpPoses[len] = offset + 1;
if (len <= kNumTableBits)
{
offset -= _poses[len];
UInt32 num = (UInt32)1 << (kNumTableBits - len);
UInt16 val = (UInt16)((sym << 4) | len);
UInt16 *dest = _lens + (_limits[len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
for (UInt32 k = 0; k < num; k++)
dest[k] = val;
}
}
return startPos == kMaxValue;
}
template <class TBitDecoder>
UInt32 Decode(TBitDecoder *bitStream) const throw()
{
UInt32 val = bitStream->GetValue(kNumBitsMax);
if (val < _limits[kNumTableBits])
{
UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
bitStream->MovePos((unsigned)(pair & 0xF));
return pair >> 4;
}
unsigned numBits;
for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
if (numBits > kNumBitsMax)
return 0xFFFFFFFF;
bitStream->MovePos(numBits);
UInt32 index = _poses[numBits] + ((val - _limits[numBits - 1]) >> (kNumBitsMax - numBits));
return _symbols[index];
}
template <class TBitDecoder>
UInt32 DecodeFull(TBitDecoder *bitStream) const throw()
{
UInt32 val = bitStream->GetValue(kNumBitsMax);
if (val < _limits[kNumTableBits])
{
UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
bitStream->MovePos((unsigned)(pair & 0xF));
return pair >> 4;
}
unsigned numBits;
for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
bitStream->MovePos(numBits);
UInt32 index = _poses[numBits] + ((val - _limits[numBits - 1]) >> (kNumBitsMax - numBits));
return _symbols[index];
}
};
template <UInt32 m_NumSymbols>
class CDecoder7b
{
Byte _lens[1 << 7];
public:
bool Build(const Byte *lens) throw()
{
const unsigned kNumBitsMax = 7;
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
UInt32 _poses[kNumBitsMax + 1];
UInt32 _limits[kNumBitsMax + 1];
unsigned i;
for (i = 0; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
UInt32 sym;
for (sym = 0; sym < m_NumSymbols; sym++)
lenCounts[lens[sym]]++;
lenCounts[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
for (i = 1; i <= kNumBitsMax; i++)
{
startPos += lenCounts[i] << (kNumBitsMax - i);
if (startPos > kMaxValue)
return false;
_limits[i] = startPos;
_poses[i] = _poses[i - 1] + lenCounts[i - 1];
tmpPoses[i] = _poses[i];
}
for (sym = 0; sym < m_NumSymbols; sym++)
{
unsigned len = lens[sym];
if (len == 0)
continue;
unsigned offset = tmpPoses[len];
tmpPoses[len] = offset + 1;
{
offset -= _poses[len];
UInt32 num = (UInt32)1 << (kNumBitsMax - len);
Byte val = (Byte)((sym << 3) | len);
Byte *dest = _lens + (_limits[len - 1]) + (offset << (kNumBitsMax - len));
for (UInt32 k = 0; k < num; k++)
dest[k] = val;
}
}
{
UInt32 limit = _limits[kNumBitsMax];
UInt32 num = ((UInt32)1 << kNumBitsMax) - limit;
Byte *dest = _lens + limit;
for (UInt32 k = 0; k < num; k++)
dest[k] = (Byte)(0x1F << 3);
}
return true;
}
template <class TBitDecoder>
UInt32 DecodeSymbol(TBitDecoder *bitStream)
UInt32 Decode(TBitDecoder *bitStream) const throw()
{
unsigned numBits;
UInt32 val = bitStream->GetValue(kNumBitsMax);
if (val < m_Limits[kNumTableBits])
numBits = m_Lengths[val >> (kNumBitsMax - kNumTableBits)];
else
for (numBits = kNumTableBits + 1; val >= m_Limits[numBits]; numBits++);
bitStream->MovePos(numBits);
UInt32 index = m_Positions[numBits] + ((val - m_Limits[numBits - 1]) >> (kNumBitsMax - numBits));
if (index >= m_NumSymbols)
// throw CDecoderException(); // test it
return 0xFFFFFFFF;
return m_Symbols[index];
UInt32 val = bitStream->GetValue(7);
UInt32 pair = _lens[val];
bitStream->MovePos((unsigned)(pair & 0x7));
return pair >> 3;
}
};

View File

@@ -71,7 +71,7 @@ bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec)
if (!CheckCodeLens(lens, NPT))
return false;
return _decoderT.SetCodeLengths(lens);
return _decoderT.Build(lens);
}
}
@@ -101,7 +101,7 @@ bool CCoder::ReadC()
{
UInt32 c = (unsigned)_symbolT;
if (_symbolT < 0)
c = _decoderT.DecodeSymbol(&_inBitStream);
c = _decoderT.Decode(&_inBitStream);
if (c <= 2)
{
@@ -129,7 +129,7 @@ bool CCoder::ReadC()
if (!CheckCodeLens(lens, NC))
return false;
return _decoderC.SetCodeLengths(lens);
return _decoderC.Build(lens);
}
}
@@ -169,7 +169,7 @@ HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
UInt32 number = (unsigned)_symbolC;
if (_symbolC < 0)
number = _decoderC.DecodeSymbol(&_inBitStream);
number = _decoderC.Decode(&_inBitStream);
if (number < 256)
{
@@ -182,7 +182,7 @@ HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
UInt32 dist = (unsigned)_symbolT;
if (_symbolT < 0)
dist = _decoderT.DecodeSymbol(&_inBitStream);
dist = _decoderT.Decode(&_inBitStream);
if (dist > 1)
{

View File

@@ -0,0 +1,573 @@
// 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 {
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 (;;)
{
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 + kSave];
data[size + kSave] = 0xE8;
Int32 last_x86_pos = -k_x86_TransOffset - 1;
// first byte is ignored
Int32 i = 0;
for (;;)
{
const 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;
Byte b = p[0];
if (b == 0x48)
{
if (p[1] == 0x8B)
{
if ((p[2] & 0xF7) != 0x5)
continue;
// MOV RAX / RCX, [RIP + disp32]
}
else if (p[1] == 0x8D) // LEA
{
if ((p[2] & 0x7) != 0x5)
continue;
// LEA R**, []
}
else
continue;
codeLen = 3;
}
else if (b == 0x4C)
{
if (p[1] != 0x8D || (p[2] & 0x7) != 0x5)
continue;
// LEA R*, []
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;
{
const Byte *p2 = p + codeLen;
UInt32 n = GetUi32(p2);
if (i - last_x86_pos <= maxTransOffset)
{
n -= i;
SetUi32(p2, n);
}
target = history + (((UInt32)i + n) & 0xFFFF);
}
i += codeLen + sizeof(UInt32) - 1;
if (i - *target <= k_x86_WindowSize)
last_x86_pos = i;
*target = i;
}
data[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);
{
{
unsigned i;
for (i = 0 ; i < k_NumReps + 1; i++)
_reps[i] = i + 1;
for (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)
{
UInt32 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)
{
UInt32 number;
HUFF_DEC(number, m_PosDecoder);
LIMIT_CHECK
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;
}
}
}
UInt32 lenSlot;
HUFF_DEC(lenSlot, m_LenDecoder);
LIMIT_CHECK
UInt32 len = g_LenBases[lenSlot];
{
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;
UInt32 power;
UInt32 distance32;
if (_rc.Decode(&deltaRepStates[0], k_NumRepProbs, deltaRepProbs[0]) == 0)
{
HUFF_DEC(power, m_PowerDecoder);
LIMIT_CHECK
UInt32 number;
HUFF_DEC(number, m_DeltaDecoder);
LIMIT_CHECK
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);
}
UInt32 dist = (distance32 << power);
UInt32 lenSlot;
HUFF_DEC(lenSlot, m_LenDecoder);
LIMIT_CHECK
UInt32 len = g_LenBases[lenSlot];
{
unsigned numDirectBits = k_LenDirectBits[lenSlot];
READ_BITS_CHECK(numDirectBits);
len += _bs.ReadBits32(numDirectBits);
}
// LIMIT_CHECK
if (len > outSize - _pos)
return S_FALSE;
if (dist > _pos)
return S_FALSE;
size_t span = (size_t)1 << power;
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;
}
}}

View File

@@ -0,0 +1,271 @@
// LzmsDecoder.h
// The code is based on LZMS description from wimlib code
#ifndef __LZMS_DECODER_H
#define __LZMS_DECODER_H
// #define SHOW_DEBUG_INFO
#ifdef SHOW_DEBUG_INFO
#include <stdio.h>
#define PRF(x) x
#else
// #define PRF(x)
#endif
#include "../../../C/CpuArch.h"
#include "../../../C/HuffEnc.h"
#include "../../Common/MyBuffer.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "HuffmanDecoder.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;
}
UInt32 GetValue(unsigned numBits) const
{
UInt32 v = ((UInt32)_buf[-1] << 16) | ((UInt32)_buf[-2] << 8) | (UInt32)_buf[-3];
v >>= (24 - numBits - _bitPos);
return v & ((1 << numBits) - 1);
}
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;
}
};
const unsigned k_NumLitSyms = 256;
const unsigned k_NumLenSyms = 54;
const unsigned k_NumPosSyms = 799;
const unsigned k_NumPowerSyms = 8;
const unsigned k_NumProbBits = 6;
const unsigned k_ProbLimit = 1 << k_NumProbBits;
const unsigned k_InitialProb = 48;
const UInt32 k_InitialHist = 0x55555555;
const unsigned k_NumReps = 3;
const unsigned k_NumMainProbs = 16;
const unsigned k_NumMatchProbs = 32;
const unsigned k_NumRepProbs = 64;
const unsigned k_NumHuffmanBits = 15;
template <UInt32 m_NumSyms, UInt32 m_RebuildFreq, unsigned numTableBits>
class CHuffDecoder: public NCompress::NHuffman::CDecoder<k_NumHuffmanBits, m_NumSyms, numTableBits>
{
public:
UInt32 RebuildRem;
UInt32 NumSyms;
UInt32 Freqs[m_NumSyms];
void Generate() throw()
{
UInt32 vals[m_NumSyms];
Byte levels[m_NumSyms];
// We need to check that our algorithm is OK, when optimal Huffman tree uses more than 15 levels !!!
Huffman_Generate(Freqs, vals, levels, NumSyms, k_NumHuffmanBits);
/*
for (UInt32 i = NumSyms; i < m_NumSyms; i++)
levels[i] = 0;
*/
this->BuildFull(levels, NumSyms);
}
void Rebuild() throw()
{
Generate();
RebuildRem = m_RebuildFreq;
UInt32 num = NumSyms;
for (UInt32 i = 0; i < num; i++)
Freqs[i] = (Freqs[i] >> 1) + 1;
}
public:
void Init(UInt32 numSyms = m_NumSyms) throw()
{
RebuildRem = m_RebuildFreq;
NumSyms = numSyms;
for (UInt32 i = 0; i < numSyms; i++)
Freqs[i] = 1;
// for (; i < m_NumSyms; i++) Freqs[i] = 0;
Generate();
}
};
struct CProbEntry
{
UInt32 Prob;
UInt64 Hist;
void Init()
{
Prob = k_InitialProb;
Hist = k_InitialHist;
}
UInt32 GetProb() const throw()
{
UInt32 prob = Prob;
if (prob == 0)
prob = 1;
else if (prob == k_ProbLimit)
prob = k_ProbLimit - 1;
return prob;
}
void Update(unsigned bit) throw()
{
Prob += (Int32)(Hist >> (k_ProbLimit - 1)) - (Int32)bit;
Hist = (Hist << 1) | bit;
}
};
struct CRangeDecoder
{
UInt32 range;
UInt32 code;
const Byte *cur;
// const Byte *end;
void Init(const Byte *data, size_t /* size */) throw()
{
range = 0xFFFFFFFF;
code = (((UInt32)GetUi16(data)) << 16) | GetUi16(data + 2);
cur = data + 4;
// end = data + size;
}
void Normalize()
{
if (range <= 0xFFFF)
{
range <<= 16;
code <<= 16;
// if (cur >= end) throw 1;
code |= GetUi16(cur);
cur += 2;
}
}
unsigned Decode(UInt32 *state, UInt32 numStates, struct CProbEntry *probs)
{
UInt32 st = *state;
CProbEntry *entry = &probs[st];
st = (st << 1) & (numStates - 1);
UInt32 prob = entry->GetProb();
if (range <= 0xFFFF)
{
range <<= 16;
code <<= 16;
// if (cur >= end) throw 1;
code |= GetUi16(cur);
cur += 2;
}
UInt32 bound = (range >> k_NumProbBits) * prob;
if (code < bound)
{
range = bound;
*state = st;
entry->Update(0);
return 0;
}
else
{
range -= bound;
code -= bound;
*state = st | 1;
entry->Update(1);
return 1;
}
}
};
class CDecoder
{
// CRangeDecoder _rc;
// CBitDecoder _bs;
size_t _pos;
UInt32 _reps[k_NumReps + 1];
UInt64 _deltaReps[k_NumReps + 1];
UInt32 mainState;
UInt32 matchState;
UInt32 lzRepStates[k_NumReps];
UInt32 deltaRepStates[k_NumReps];
struct CProbEntry mainProbs[k_NumMainProbs];
struct CProbEntry matchProbs[k_NumMatchProbs];
struct CProbEntry lzRepProbs[k_NumReps][k_NumRepProbs];
struct CProbEntry deltaRepProbs[k_NumReps][k_NumRepProbs];
CHuffDecoder<k_NumLitSyms, 1024, 9> m_LitDecoder;
CHuffDecoder<k_NumPosSyms, 1024, 9> m_PosDecoder;
CHuffDecoder<k_NumLenSyms, 512, 8> m_LenDecoder;
CHuffDecoder<k_NumPowerSyms, 512, 6> m_PowerDecoder;
CHuffDecoder<k_NumPosSyms, 1024, 9> m_DeltaDecoder;
Int32 *_x86_history;
HRESULT CodeReal(const Byte *in, size_t inSize, Byte *out, size_t outSize);
public:
CDecoder();
~CDecoder();
HRESULT Code(const Byte *in, size_t inSize, Byte *out, size_t outSize);
const size_t GetUnpackSize() const { return _pos; }
};
}}
#endif

View File

@@ -6,55 +6,51 @@
namespace NCompress {
namespace NLzx {
const unsigned kBlockType_NumBits = 3;
const unsigned kBlockType_Verbatim = 1;
const unsigned kBlockType_Aligned = 2;
const unsigned kBlockType_Uncompressed = 3;
const unsigned kNumHuffmanBits = 16;
const UInt32 kNumRepDistances = 3;
const unsigned kNumReps = 3;
const UInt32 kNumLenSlots = 8;
const UInt32 kMatchMinLen = 2;
const UInt32 kNumLenSymbols = 249;
const UInt32 kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1;
const unsigned kNumLenSlots = 8;
const unsigned kMatchMinLen = 2;
const unsigned kNumLenSymbols = 249;
const unsigned kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1;
const unsigned kNumAlignLevelBits = 3;
const unsigned kNumAlignBits = 3;
const UInt32 kAlignTableSize = 1 << kNumAlignBits;
const unsigned kAlignTableSize = 1 << kNumAlignBits;
const UInt32 kNumPosSlots = 50;
const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
const unsigned kNumPosSlots = 50;
const unsigned kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
const UInt32 kMainTableSize = 256 + kNumPosLenSlots;
const UInt32 kLevelTableSize = 20;
const UInt32 kMaxTableSize = kMainTableSize;
const unsigned kMainTableSize = 256 + kNumPosLenSlots;
const unsigned kLevelTableSize = 20;
const unsigned kMaxTableSize = kMainTableSize;
const unsigned kNumBlockTypeBits = 3;
const unsigned kBlockTypeVerbatim = 1;
const unsigned kBlockTypeAligned = 2;
const unsigned kBlockTypeUncompressed = 3;
const unsigned kNumLevelBits = 4;
const unsigned kUncompressedBlockSizeNumBits = 24;
const unsigned kLevelSym_Zero1 = 17;
const unsigned kLevelSym_Zero2 = 18;
const unsigned kLevelSym_Same = 19;
const unsigned kNumBitsForPreTreeLevel = 4;
const unsigned kLevelSym_Zero1_Start = 4;
const unsigned kLevelSym_Zero1_NumBits = 4;
const unsigned kLevelSymbolZeros = 17;
const unsigned kLevelSymbolZerosBig = 18;
const unsigned kLevelSymbolSame = 19;
const unsigned kLevelSym_Zero2_Start = kLevelSym_Zero1_Start + (1 << kLevelSym_Zero1_NumBits);
const unsigned kLevelSym_Zero2_NumBits = 5;
const unsigned kLevelSymbolZerosStartValue = 4;
const unsigned kLevelSymbolZerosNumBits = 4;
const unsigned kLevelSymbolZerosBigStartValue = kLevelSymbolZerosStartValue +
(1 << kLevelSymbolZerosNumBits);
const unsigned kLevelSymbolZerosBigNumBits = 5;
const unsigned kLevelSymbolSameNumBits = 1;
const unsigned kLevelSymbolSameStartValue = 4;
const unsigned kNumBitsForAlignLevel = 3;
const unsigned kNumDictionaryBitsMin = 15;
const unsigned kNumDictionaryBitsMax = 21;
const UInt32 kDictionarySizeMax = (1 << kNumDictionaryBitsMax);
const unsigned kLevelSym_Same_NumBits = 1;
const unsigned kLevelSym_Same_Start = 4;
const unsigned kNumDictBits_Min = 15;
const unsigned kNumDictBits_Max = 21;
const UInt32 kDictSize_Max = (UInt32)1 << kNumDictBits_Max;
const unsigned kNumLinearPosSlotBits = 17;
const UInt32 kNumPowerPosSlots = 0x26;
const unsigned kNumPowerPosSlots = 38;
}}

View File

@@ -1,90 +0,0 @@
// Lzx86Converter.cpp
#include "StdAfx.h"
#include "../../Common/Defs.h"
#include "Lzx86Converter.h"
namespace NCompress {
namespace NLzx {
static const UInt32 kResidue = 6 + 4;
void Cx86ConvertOutStream::MakeTranslation()
{
if (_pos <= kResidue)
return;
UInt32 numBytes = _pos - kResidue;
Byte *buf = _buf;
for (UInt32 i = 0; i < numBytes;)
{
if (buf[i++] == 0xE8)
{
Int32 absValue = 0;
unsigned j;
for (j = 0; j < 4; j++)
absValue += (UInt32)buf[i + j] << (j * 8);
Int32 pos = (Int32)(_processedSize + i - 1);
if (absValue >= -pos && absValue < (Int32)_translationSize)
{
UInt32 offset = (absValue >= 0) ?
absValue - pos :
absValue + _translationSize;
for (j = 0; j < 4; j++)
{
buf[i + j] = (Byte)(offset & 0xFF);
offset >>= 8;
}
}
i += 4;
}
}
}
STDMETHODIMP Cx86ConvertOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
if (!_translationMode)
return _stream->Write(data, size, processedSize);
UInt32 realProcessedSize = 0;
while (realProcessedSize < size)
{
UInt32 writeSize = MyMin(size - realProcessedSize, kUncompressedBlockSize - _pos);
memcpy(_buf + _pos, (const Byte *)data + realProcessedSize, writeSize);
_pos += writeSize;
realProcessedSize += writeSize;
if (_pos == kUncompressedBlockSize)
{
RINOK(Flush());
}
}
if (processedSize)
*processedSize = realProcessedSize;
return S_OK;
}
HRESULT Cx86ConvertOutStream::Flush()
{
if (_pos == 0)
return S_OK;
if (_translationMode)
MakeTranslation();
UInt32 pos = 0;
do
{
UInt32 processed;
RINOK(_stream->Write(_buf + pos, _pos - pos, &processed));
if (processed == 0)
return E_FAIL;
pos += processed;
}
while (pos < _pos);
_processedSize += _pos;
_pos = 0;
_translationMode = (_translationMode && (_processedSize < ((UInt32)1 << 30)));
return S_OK;
}
}}

View File

@@ -1,45 +0,0 @@
// Lzx86Converter.h
#ifndef __LZX_86_CONVERTER_H
#define __LZX_86_CONVERTER_H
#include "../../Common/MyCom.h"
#include "../IStream.h"
namespace NCompress {
namespace NLzx {
const unsigned kUncompressedBlockSize = (unsigned)1 << 15;
class Cx86ConvertOutStream:
public ISequentialOutStream,
public CMyUnknownImp
{
ISequentialOutStream *_stream;
UInt32 _processedSize;
UInt32 _pos;
UInt32 _translationSize;
bool _translationMode;
Byte _buf[kUncompressedBlockSize];
void MakeTranslation();
public:
void SetStream(ISequentialOutStream *outStream) { _stream = outStream; }
void Init(bool translationMode, UInt32 translationSize)
{
_translationMode = translationMode;
_translationSize = translationSize;
_processedSize = 0;
_pos = 0;
}
HRESULT Flush();
MY_UNKNOWN_IMP
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
};
}}
#endif

View File

@@ -2,394 +2,528 @@
#include "StdAfx.h"
#include "../../Common/Defs.h"
#include <string.h>
// #define SHOW_DEBUG_INFO
#ifdef SHOW_DEBUG_INFO
#include <stdio.h>
#define PRF(x) x
#else
#define PRF(x)
#endif
#include "../../../C/Alloc.h"
#include "LzxDecoder.h"
namespace NCompress {
namespace NLzx {
const int kLenIdNeedInit = -2;
static void x86_Filter(Byte *data, UInt32 size, UInt32 processedSize, UInt32 translationSize)
{
const UInt32 kResidue = 10;
if (size <= kResidue)
return;
size -= kResidue;
Byte save = data[size + 4];
data[size + 4] = 0xE8;
for (UInt32 i = 0;;)
{
const Byte *p = data + i;
for (;;)
{
if (*p++ == 0xE8) break;
if (*p++ == 0xE8) break;
if (*p++ == 0xE8) break;
if (*p++ == 0xE8) break;
}
i = (UInt32)(p - data);
if (i > size)
break;
{
Int32 v = GetUi32(p);
Int32 pos = (Int32)((Int32)1 - (Int32)(processedSize + i));
i += 4;
if (v >= pos && v < (Int32)translationSize)
{
v += (v >= 0 ? pos : translationSize);
SetUi32(p, v);
}
}
}
data[size + 4] = save;
}
CDecoder::CDecoder(bool wimMode):
_keepHistory(false),
_skipByte(false),
_wimMode(wimMode)
_win(NULL),
_keepHistory(false),
_skipByte(false),
_wimMode(wimMode),
_numDictBits(15),
_unpackBlockSize(0),
_x86_buf(NULL),
_x86_translationSize(0),
KeepHistoryForNext(true),
NeedAlloc(true),
_unpackedData(NULL)
{
m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream;
m_x86ConvertOutStream = m_x86ConvertOutStreamSpec;
}
/*
void CDecoder::ReleaseStreams()
CDecoder::~CDecoder()
{
m_OutWindowStream.ReleaseStream();
m_InBitStream.ReleaseStream();
m_x86ConvertOutStreamSpec->ReleaseStream();
}
*/
STDMETHODIMP CDecoder::Flush()
{
RINOK(m_OutWindowStream.Flush());
return m_x86ConvertOutStreamSpec->Flush();
if (NeedAlloc)
::MidFree(_win);
::MidFree(_x86_buf);
}
UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
HRESULT CDecoder::Flush()
{
if (_x86_translationSize != 0)
{
Byte *destData = _win + _writePos;
UInt32 curSize = _pos - _writePos;
if (KeepHistoryForNext)
{
if (!_x86_buf)
{
// we must change it to support another chunk sizes
const size_t kChunkSize = (size_t)1 << 15;
if (curSize > kChunkSize)
return E_NOTIMPL;
_x86_buf = (Byte *)::MidAlloc(kChunkSize);
if (!_x86_buf)
return E_OUTOFMEMORY;
}
memcpy(_x86_buf, destData, curSize);
_unpackedData = _x86_buf;
destData = _x86_buf;
}
x86_Filter(destData, (UInt32)curSize, _x86_processedSize, _x86_translationSize);
_x86_processedSize += (UInt32)curSize;
if (_x86_processedSize >= ((UInt32)1 << 30))
_x86_translationSize = 0;
}
return S_OK;
}
UInt32 CDecoder::ReadBits(unsigned numBits) { return _bitStream.ReadBitsSmall(numBits); }
#define RIF(x) { if (!(x)) return false; }
bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols)
bool CDecoder::ReadTable(Byte *levels, unsigned numSymbols)
{
Byte levelLevels[kLevelTableSize];
UInt32 i;
for (i = 0; i < kLevelTableSize; i++)
levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel);
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
unsigned num = 0;
Byte symbol = 0;
for (i = 0; i < numSymbols;)
{
if (num != 0)
Byte levels2[kLevelTableSize];
for (unsigned i = 0; i < kLevelTableSize; i++)
levels2[i] = (Byte)ReadBits(kNumLevelBits);
RIF(_levelDecoder.Build(levels2));
}
unsigned i = 0;
do
{
UInt32 sym = _levelDecoder.Decode(&_bitStream);
if (sym <= kNumHuffmanBits)
{
lastLevels[i] = newLevels[i] = symbol;
i++;
num--;
int delta = (int)levels[i] - (int)sym;
delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0;
levels[i++] = (Byte)delta;
continue;
}
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
if (number == kLevelSymbolZeros)
unsigned num;
Byte symbol;
if (sym < kLevelSym_Same)
{
num = kLevelSymbolZerosStartValue + (unsigned)ReadBits(kLevelSymbolZerosNumBits);
sym -= kLevelSym_Zero1;
num = kLevelSym_Zero1_Start + ((unsigned)sym << kLevelSym_Zero1_NumBits) +
(unsigned)ReadBits(kLevelSym_Zero1_NumBits + sym);
symbol = 0;
}
else if (number == kLevelSymbolZerosBig)
else if (sym == kLevelSym_Same)
{
num = kLevelSymbolZerosBigStartValue + (unsigned)ReadBits(kLevelSymbolZerosBigNumBits);
symbol = 0;
}
else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)
{
if (number <= kNumHuffmanBits)
num = 1;
else
{
num = kLevelSymbolSameStartValue + (unsigned)ReadBits(kLevelSymbolSameNumBits);
number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
if (number > kNumHuffmanBits)
return false;
}
symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1));
num = kLevelSym_Same_Start + (unsigned)ReadBits(kLevelSym_Same_NumBits);
sym = _levelDecoder.Decode(&_bitStream);
if (sym > kNumHuffmanBits)
return false;
int delta = (int)levels[i] - (int)sym;
delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0;
symbol = (Byte)delta;
}
else
return false;
unsigned limit = i + num;
if (limit > numSymbols)
return false;
do
levels[i++] = symbol;
while (i < limit);
}
while (i < numSymbols);
return true;
}
bool CDecoder::ReadTables(void)
{
Byte newLevels[kMaxTableSize];
{
if (_skipByte)
m_InBitStream.DirectReadByte();
m_InBitStream.Normalize();
unsigned blockType = (unsigned)ReadBits(kNumBlockTypeBits);
if (blockType > kBlockTypeUncompressed)
return false;
if (_wimMode)
if (ReadBits(1) == 1)
m_UnCompressedBlockSize = (1 << 15);
else
m_UnCompressedBlockSize = ReadBits(16);
else
m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits);
m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed);
_skipByte = (m_IsUncompressedBlock && ((m_UnCompressedBlockSize & 1) != 0));
if (m_IsUncompressedBlock)
{
ReadBits(16 - m_InBitStream.GetBitPosition());
if (!m_InBitStream.ReadUInt32(m_RepDistances[0]))
if (_bitStream.DirectReadByte() != 0)
return false;
m_RepDistances[0]--;
for (unsigned i = 1; i < kNumRepDistances; i++)
}
_bitStream.NormalizeBig();
unsigned blockType = (unsigned)ReadBits(kBlockType_NumBits);
if (blockType > kBlockType_Uncompressed)
return false;
_unpackBlockSize = (1 << 15);
if (!_wimMode || ReadBits(1) == 0)
{
_unpackBlockSize = ReadBits(16);
// wimlib supports chunks larger than 32KB (unsupported my MS wim).
if (!_wimMode || _numDictBits >= 16)
{
UInt32 rep = 0;
for (unsigned j = 0; j < 4; j++)
rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j);
m_RepDistances[i] = rep - 1;
_unpackBlockSize <<= 8;
_unpackBlockSize |= ReadBits(8);
}
}
PRF(printf("\nBlockSize = %6d %s ", _unpackBlockSize, (_pos & 1) ? "@@@" : " "));
_isUncompressedBlock = (blockType == kBlockType_Uncompressed);
_skipByte = false;
if (_isUncompressedBlock)
{
_skipByte = ((_unpackBlockSize & 1) != 0);
PRF(printf(" UncompressedBlock "));
if (_unpackBlockSize & 1)
{
PRF(printf(" ######### "));
}
if (!_bitStream.PrepareUncompressed())
return false;
if (_bitStream.GetRem() < kNumReps * 4)
return false;
for (unsigned i = 0; i < kNumReps; i++)
{
UInt32 rep = _bitStream.ReadUInt32();
if (rep > _winSize)
return false;
_reps[i] = rep;
}
return true;
}
m_AlignIsUsed = (blockType == kBlockTypeAligned);
if (m_AlignIsUsed)
_numAlignBits = 64;
if (blockType == kBlockType_Aligned)
{
Byte levels[kAlignTableSize];
_numAlignBits = kNumAlignBits;
for (unsigned i = 0; i < kAlignTableSize; i++)
newLevels[i] = (Byte)ReadBits(kNumBitsForAlignLevel);
RIF(m_AlignDecoder.SetCodeLengths(newLevels));
levels[i] = (Byte)ReadBits(kNumAlignLevelBits);
RIF(_alignDecoder.Build(levels));
}
}
RIF(ReadTable(m_LastMainLevels, newLevels, 256));
RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots));
for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++)
newLevels[i] = 0;
RIF(m_MainDecoder.SetCodeLengths(newLevels));
RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols));
return m_LenDecoder.SetCodeLengths(newLevels);
}
class CDecoderFlusher
{
CDecoder *m_Decoder;
public:
bool NeedFlush;
CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
~CDecoderFlusher()
{
if (NeedFlush)
m_Decoder->Flush();
// m_Decoder->ReleaseStreams();
}
};
void CDecoder::ClearPrevLevels()
{
unsigned i;
for (i = 0; i < kMainTableSize; i++)
m_LastMainLevels[i] = 0;
for (i = 0; i < kNumLenSymbols; i++)
m_LastLenLevels[i] = 0;
RIF(ReadTable(_mainLevels, 256));
RIF(ReadTable(_mainLevels + 256, _numPosLenSlots));
unsigned end = 256 + _numPosLenSlots;
memset(_mainLevels + end, 0, kMainTableSize - end);
RIF(_mainDecoder.Build(_mainLevels));
RIF(ReadTable(_lenLevels, kNumLenSymbols));
return _lenDecoder.Build(_lenLevels);
}
HRESULT CDecoder::CodeSpec(UInt32 curSize)
{
if (_remainLen == kLenIdNeedInit)
if (!_keepHistory || !_isUncompressedBlock)
_bitStream.NormalizeBig();
if (!_keepHistory)
{
_remainLen = 0;
m_InBitStream.Init();
if (!_keepHistory || !m_IsUncompressedBlock)
m_InBitStream.Normalize();
if (!_keepHistory)
_skipByte = false;
_unpackBlockSize = 0;
memset(_mainLevels, 0, kMainTableSize);
memset(_lenLevels, 0, kNumLenSymbols);
{
_skipByte = false;
m_UnCompressedBlockSize = 0;
ClearPrevLevels();
UInt32 i86TranslationSize = 12000000;
bool translationMode = true;
_x86_translationSize = 12000000;
if (!_wimMode)
{
translationMode = (ReadBits(1) != 0);
if (translationMode)
_x86_translationSize = 0;
if (ReadBits(1) != 0)
{
i86TranslationSize = ReadBits(16) << 16;
i86TranslationSize |= ReadBits(16);
UInt32 v = ReadBits(16) << 16;
v |= ReadBits(16);
_x86_translationSize = v;
}
}
m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize);
for (unsigned i = 0 ; i < kNumRepDistances; i++)
m_RepDistances[i] = 0;
_x86_processedSize = 0;
}
}
while (_remainLen > 0 && curSize > 0)
{
m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0]));
_remainLen--;
curSize--;
_reps[0] = 1;
_reps[1] = 1;
_reps[2] = 1;
}
while (curSize > 0)
{
if (m_UnCompressedBlockSize == 0)
if (_bitStream.WasExtraReadError_Fast())
return S_FALSE;
if (_unpackBlockSize == 0)
{
if (!ReadTables())
return S_FALSE;
UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize);
curSize -= next;
m_UnCompressedBlockSize -= next;
if (m_IsUncompressedBlock)
{
while (next > 0)
{
m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte());
next--;
}
continue;
}
else while (next > 0)
UInt32 next = _unpackBlockSize;
if (next > curSize)
next = curSize;
if (_isUncompressedBlock)
{
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
if (number < 256)
size_t rem = _bitStream.GetRem();
if (rem == 0)
return S_FALSE;
if (next > rem)
next = (UInt32)rem;
_bitStream.CopyTo(_win + _pos, next);
_pos += next;
curSize -= next;
_unpackBlockSize -= next;
/* we don't know where skipByte can be placed, if it's end of chunk:
1) in current chunk - there are such cab archives, if chunk is last
2) in next chunk - are there such archives ? */
if (_skipByte
&& _unpackBlockSize == 0
&& curSize == 0
&& _bitStream.IsOneDirectByteLeft())
{
m_OutWindowStream.PutByte((Byte)number);
next--;
}
else
{
UInt32 posLenSlot = number - 256;
if (posLenSlot >= m_NumPosLenSlots)
_skipByte = false;
if (_bitStream.DirectReadByte() != 0)
return S_FALSE;
UInt32 posSlot = posLenSlot / kNumLenSlots;
UInt32 lenSlot = posLenSlot % kNumLenSlots;
}
continue;
}
curSize -= next;
_unpackBlockSize -= next;
Byte *win = _win;
while (next > 0)
{
if (_bitStream.WasExtraReadError_Fast())
return S_FALSE;
UInt32 sym = _mainDecoder.Decode(&_bitStream);
if (sym < 256)
{
win[_pos++] = (Byte)sym;
next--;
continue;
}
{
sym -= 256;
if (sym >= _numPosLenSlots)
return S_FALSE;
UInt32 posSlot = sym / kNumLenSlots;
UInt32 lenSlot = sym % kNumLenSlots;
UInt32 len = kMatchMinLen + lenSlot;
if (lenSlot == kNumLenSlots - 1)
{
UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream);
UInt32 lenTemp = _lenDecoder.Decode(&_bitStream);
if (lenTemp >= kNumLenSymbols)
return S_FALSE;
len += lenTemp;
len = kMatchMinLen + kNumLenSlots - 1 + lenTemp;
}
if (posSlot < kNumRepDistances)
UInt32 dist;
if (posSlot < kNumReps)
{
UInt32 distance = m_RepDistances[posSlot];
m_RepDistances[posSlot] = m_RepDistances[0];
m_RepDistances[0] = distance;
dist = _reps[posSlot];
_reps[posSlot] = _reps[0];
_reps[0] = dist;
}
else
{
UInt32 distance;
unsigned numDirectBits;
if (posSlot < kNumPowerPosSlots)
{
numDirectBits = (unsigned)(posSlot >> 1) - 1;
distance = ((2 | (posSlot & 1)) << numDirectBits);
dist = ((2 | (posSlot & 1)) << numDirectBits);
}
else
{
numDirectBits = kNumLinearPosSlotBits;
distance = ((posSlot - 0x22) << kNumLinearPosSlotBits);
dist = ((posSlot - 0x22) << kNumLinearPosSlotBits);
}
if (m_AlignIsUsed && numDirectBits >= kNumAlignBits)
if (numDirectBits >= _numAlignBits)
{
distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits);
UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
dist += (_bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits);
UInt32 alignTemp = _alignDecoder.Decode(&_bitStream);
if (alignTemp >= kAlignTableSize)
return S_FALSE;
distance += alignTemp;
dist += alignTemp;
}
else
distance += m_InBitStream.ReadBits(numDirectBits);
m_RepDistances[2] = m_RepDistances[1];
m_RepDistances[1] = m_RepDistances[0];
m_RepDistances[0] = distance - kNumRepDistances;
dist += _bitStream.ReadBitsBig(numDirectBits);
dist -= kNumReps - 1;
_reps[2] = _reps[1];
_reps[1] = _reps[0];
_reps[0] = dist;
}
UInt32 locLen = len;
if (locLen > next)
locLen = next;
if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen))
if (len > next)
return S_FALSE;
len -= locLen;
next -= locLen;
if (len != 0)
if (dist > _pos && !_overDict)
return S_FALSE;
Byte *dest = win + _pos;
const UInt32 mask = (_winSize - 1);
UInt32 srcPos = (_pos - dist) & mask;
next -= len;
if (len > _winSize - srcPos)
{
_remainLen = (int)len;
return S_OK;
_pos += len;
do
{
*dest++ = win[srcPos++];
srcPos &= mask;
}
while (--len);
}
else
{
ptrdiff_t src = (ptrdiff_t)srcPos - (ptrdiff_t)_pos;
_pos += len;
const Byte *lim = dest + len;
*(dest) = *(dest + src);
dest++;
do
*(dest) = *(dest + src);
while (++dest != lim);
}
}
}
}
if (!_bitStream.WasFinishedOK())
return S_FALSE;
return S_OK;
}
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
HRESULT CDecoder::Code(const Byte *inData, size_t inSize, UInt32 outSize)
{
if (outSize == NULL)
return E_INVALIDARG;
UInt64 size = *outSize;
// RINOK(SetInStream(inStream));
m_InBitStream.SetStream(inStream);
m_x86ConvertOutStreamSpec->SetStream(outStream);
m_OutWindowStream.SetStream(m_x86ConvertOutStream);
RINOK(SetOutStreamSize(outSize));
CDecoderFlusher flusher(this);
const UInt64 start = m_OutWindowStream.GetProcessedSize();
for (;;)
if (_pos == _winSize)
{
UInt32 curSize = 1 << 18;
UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start);
if (curSize > rem)
curSize = (UInt32)rem;
if (curSize == 0)
break;
RINOK(CodeSpec(curSize));
if (progress != NULL)
_pos = 0;
_overDict = true;
}
if (!_keepHistory)
{
_pos = 0;
_overDict = false;
}
_writePos = _pos;
_unpackedData = _win + _pos;
if (outSize > _winSize - _pos)
return S_FALSE;
PRF(printf("\ninSize = %d", inSize));
if ((inSize & 1) != 0)
{
PRF(printf(" ---------"));
}
if (inSize < 1)
return S_FALSE;
_bitStream.Init(inData, inSize);
HRESULT res = CodeSpec(outSize);
HRESULT res2 = Flush();
return (res == S_OK ? res2 : res);
}
HRESULT CDecoder::SetParams2(unsigned numDictBits)
{
_numDictBits = numDictBits;
if (numDictBits < kNumDictBits_Min || numDictBits > kNumDictBits_Max)
return E_INVALIDARG;
unsigned numPosSlots = (numDictBits < 20) ?
numDictBits * 2 :
34 + ((unsigned)1 << (numDictBits - 17));
_numPosLenSlots = numPosSlots * kNumLenSlots;
return S_OK;
}
HRESULT CDecoder::SetParams_and_Alloc(unsigned numDictBits)
{
RINOK(SetParams2(numDictBits));
UInt32 newWinSize = (UInt32)1 << numDictBits;
if (NeedAlloc)
{
if (!_win || newWinSize != _winSize)
{
UInt64 inSize = m_InBitStream.GetProcessedSize();
UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
::MidFree(_win);
_winSize = 0;
_win = (Byte *)::MidAlloc(newWinSize);
if (!_win)
return E_OUTOFMEMORY;
}
}
flusher.NeedFlush = false;
return Flush();
}
HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
catch(...) { return S_FALSE; }
}
/*
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
{
m_InStreamRef = inStream;
m_InBitStream.SetStream(inStream);
return S_OK;
}
STDMETHODIMP CDecoder::ReleaseInStream()
{
m_InStreamRef.Release();
return S_OK;
}
*/
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
{
if (outSize == NULL)
return E_FAIL;
// flush calls m_x86ConvertOutStreamSpec->flush, so we must init x86Convert.
if (!_keepHistory)
m_x86ConvertOutStreamSpec->Init(false, 0);
_remainLen = kLenIdNeedInit;
m_OutWindowStream.Init(_keepHistory);
return S_OK;
}
HRESULT CDecoder::SetParams(unsigned numDictBits)
{
if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax)
return E_INVALIDARG;
UInt32 numPosSlots;
if (numDictBits < 20)
numPosSlots = 30 + (numDictBits - 15) * 2;
else if (numDictBits == 20)
numPosSlots = 42;
else
numPosSlots = 50;
m_NumPosLenSlots = numPosSlots * kNumLenSlots;
if (!m_OutWindowStream.Create(kDictionarySizeMax))
return E_OUTOFMEMORY;
if (!m_InBitStream.Create(1 << 16))
return E_OUTOFMEMORY;
_winSize = (UInt32)newWinSize;
return S_OK;
}

View File

@@ -3,155 +3,240 @@
#ifndef __LZX_DECODER_H
#define __LZX_DECODER_H
#include "../ICoder.h"
#include "../../../C/CpuArch.h"
#include "../Common/InBuffer.h"
#include "../../Common/MyCom.h"
#include "HuffmanDecoder.h"
#include "LzOutWindow.h"
#include "Lzx.h"
#include "Lzx86Converter.h"
namespace NCompress {
namespace NLzx {
namespace NBitStream {
const unsigned kNumBigValueBits = 8 * 4;
const unsigned kNumValueBits = 17;
const UInt32 kBitDecoderValueMask = (1 << kNumValueBits) - 1;
class CDecoder
class CBitDecoder
{
CInBuffer _stream;
UInt32 _value;
unsigned _bitPos;
UInt32 _value;
const Byte *_buf;
const Byte *_bufLim;
UInt32 _extraSize;
public:
CDecoder() {}
bool Create(UInt32 bufSize) { return _stream.Create(bufSize); }
void SetStream(ISequentialInStream *s) { _stream.SetStream(s); }
void Init()
void Init(const Byte *data, size_t size)
{
_stream.Init();
_bitPos = kNumBigValueBits;
_buf = data;
_bufLim = data + size - 1;
_bitPos = 0;
_extraSize = 0;
}
UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); }
unsigned GetBitPosition() const { return _bitPos & 0xF; }
size_t GetRem() const { return _bufLim + 1 - _buf; }
bool WasExtraReadError_Fast() const { return _extraSize > 4; }
void Normalize()
bool WasFinishedOK() const
{
for (; _bitPos >= 16; _bitPos -= 16)
if (_buf != _bufLim + 1)
return false;
if ((_bitPos >> 4) * 2 != _extraSize)
return false;
unsigned numBits = _bitPos & 15;
return (((_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1)) == 0);
}
void NormalizeSmall()
{
if (_bitPos <= 16)
{
Byte b0 = _stream.ReadByte();
Byte b1 = _stream.ReadByte();
_value = (_value << 8) | b1;
_value = (_value << 8) | b0;
UInt32 val;
if (_buf >= _bufLim)
{
val = 0xFFFF;
_extraSize += 2;
}
else
{
val = GetUi16(_buf);
_buf += 2;
}
_value = (_value << 16) | val;
_bitPos += 16;
}
}
void NormalizeBig()
{
if (_bitPos <= 16)
{
UInt32 val;
if (_buf >= _bufLim)
{
val = 0xFFFF;
_extraSize += 2;
}
else
{
val = GetUi16(_buf);
_buf += 2;
}
_value = (_value << 16) | val;
_bitPos += 16;
if (_bitPos <= 16)
{
UInt32 val;
if (_buf >= _bufLim)
{
val = 0xFFFF;
_extraSize += 2;
}
else
{
val = GetUi16(_buf);
_buf += 2;
}
_value = (_value << 16) | val;
_bitPos += 16;
}
}
}
UInt32 GetValue(unsigned numBits) const
{
return ((_value >> ((32 - kNumValueBits) - _bitPos)) & kBitDecoderValueMask) >> (kNumValueBits - numBits);
return (_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1);
}
void MovePos(unsigned numBits)
{
_bitPos += numBits;
Normalize();
_bitPos -= numBits;
NormalizeSmall();
}
UInt32 ReadBits(unsigned numBits)
UInt32 ReadBitsSmall(unsigned numBits)
{
UInt32 res = GetValue(numBits);
MovePos(numBits);
return res;
_bitPos -= numBits;
UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
NormalizeSmall();
return val;
}
UInt32 ReadBitsBig(unsigned numBits)
{
unsigned numBits0 = numBits / 2;
unsigned numBits1 = numBits - numBits0;
UInt32 res = ReadBits(numBits0) << numBits1;
return res + ReadBits(numBits1);
_bitPos -= numBits;
UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
NormalizeBig();
return val;
}
bool ReadUInt32(UInt32 &v)
bool PrepareUncompressed()
{
if (_bitPos != 0)
if (_extraSize != 0)
return false;
v = ((_value >> 16) & 0xFFFF) | ((_value << 16) & 0xFFFF0000);
_bitPos = kNumBigValueBits;
unsigned numBits = _bitPos - 16;
if (((_value >> 16) & (((UInt32)1 << numBits) - 1)) != 0)
return false;
_buf -= 2;
_bitPos = 0;
return true;
}
Byte DirectReadByte() { return _stream.ReadByte(); }
UInt32 ReadUInt32()
{
UInt32 v = GetUi32(_buf);
_buf += 4;
return v;
}
void CopyTo(Byte *dest, size_t size)
{
memcpy(dest, _buf, size);
_buf += size;
}
bool IsOneDirectByteLeft() const { return _buf == _bufLim && _extraSize == 0; }
Byte DirectReadByte()
{
if (_buf > _bufLim)
{
_extraSize++;
return 0xFF;
}
return *_buf++;
}
};
}
class CDecoder :
public ICompressCoder,
class CDecoder:
public IUnknown,
public CMyUnknownImp
{
// CMyComPtr<ISequentialInStream> m_InStreamRef;
NBitStream::CDecoder m_InBitStream;
CLzOutWindow m_OutWindowStream;
CBitDecoder _bitStream;
Byte *_win;
UInt32 _pos;
UInt32 _winSize;
UInt32 m_RepDistances[kNumRepDistances];
UInt32 m_NumPosLenSlots;
bool m_IsUncompressedBlock;
bool m_AlignIsUsed;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kNumLenSymbols> m_LenDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
Byte m_LastMainLevels[kMainTableSize];
Byte m_LastLenLevels[kNumLenSymbols];
Cx86ConvertOutStream *m_x86ConvertOutStreamSpec;
CMyComPtr<ISequentialOutStream> m_x86ConvertOutStream;
UInt32 m_UnCompressedBlockSize;
bool _keepHistory;
int _remainLen;
bool _overDict;
bool _isUncompressedBlock;
bool _skipByte;
unsigned _numAlignBits;
UInt32 _reps[kNumReps];
UInt32 _numPosLenSlots;
UInt32 _unpackBlockSize;
public:
bool KeepHistoryForNext;
bool NeedAlloc;
private:
bool _keepHistory;
bool _wimMode;
unsigned _numDictBits;
UInt32 _writePos;
Byte *_x86_buf;
UInt32 _x86_translationSize;
UInt32 _x86_processedSize;
Byte *_unpackedData;
NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> _mainDecoder;
NHuffman::CDecoder<kNumHuffmanBits, kNumLenSymbols> _lenDecoder;
NHuffman::CDecoder7b<kAlignTableSize> _alignDecoder;
NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize, 7> _levelDecoder;
Byte _mainLevels[kMainTableSize];
Byte _lenLevels[kNumLenSymbols];
HRESULT Flush();
UInt32 ReadBits(unsigned numBits);
bool ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols);
bool ReadTable(Byte *levels, unsigned numSymbols);
bool ReadTables();
void ClearPrevLevels();
HRESULT CodeSpec(UInt32 size);
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
HRESULT SetParams2(unsigned numDictBits);
public:
CDecoder(bool wimMode = false);
~CDecoder();
MY_UNKNOWN_IMP
// void ReleaseStreams();
STDMETHOD(Flush)();
HRESULT SetExternalWindow(Byte *win, unsigned numDictBits)
{
NeedAlloc = false;
_win = win;
_winSize = (UInt32)1 << numDictBits;
return SetParams2(numDictBits);
}
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
// STDMETHOD(SetInStream)(ISequentialInStream *inStream);
// STDMETHOD(ReleaseInStream)();
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
HRESULT SetParams_and_Alloc(unsigned numDictBits);
HRESULT SetParams(unsigned numDictBits);
void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
HRESULT Code(const Byte *inData, size_t inSize, UInt32 outSize);
bool WasBlockFinished() const { return _unpackBlockSize == 0; }
const Byte *GetUnpackData() const { return _unpackedData; }
const UInt32 GetUnpackSize() const { return _pos - _writePos; }
};
}}

View File

@@ -9,13 +9,81 @@
namespace NCompress {
namespace NQuantum {
static const int kLenIdNeedInit = -2;
static const unsigned kNumLenSymbols = 27;
static const unsigned kMatchMinLen = 3;
static const unsigned kNumSimplePosSlots = 4;
static const unsigned kNumSimpleLenSlots = 6;
static const UInt16 kUpdateStep = 8;
static const UInt16 kFreqSumMax = 3800;
static const unsigned kReorderCountStart = 4;
static const unsigned kReorderCount = 50;
void CModelDecoder::Init(unsigned numItems)
{
NumItems = numItems;
ReorderCount = kReorderCountStart;
for (unsigned i = 0; i < numItems; i++)
{
Freqs[i] = (UInt16)(numItems - i);
Vals[i] = (Byte)i;
}
Freqs[numItems] = 0;
}
unsigned CModelDecoder::Decode(CRangeDecoder *rc)
{
UInt32 threshold = rc->GetThreshold(Freqs[0]);
unsigned i;
for (i = 1; Freqs[i] > threshold; i++);
rc->Decode(Freqs[i], Freqs[i - 1], Freqs[0]);
unsigned res = Vals[--i];
do
Freqs[i] += kUpdateStep;
while (i--);
if (Freqs[0] > kFreqSumMax)
{
if (--ReorderCount == 0)
{
ReorderCount = kReorderCount;
for (i = 0; i < NumItems; i++)
Freqs[i] = (UInt16)(((Freqs[i] - Freqs[i + 1]) + 1) >> 1);
for (i = 0; i < NumItems - 1; i++)
for (unsigned j = i + 1; j < NumItems; j++)
if (Freqs[i] < Freqs[j])
{
UInt16 tmpFreq = Freqs[i];
Byte tmpVal = Vals[i];
Freqs[i] = Freqs[j];
Vals[i] = Vals[j];
Freqs[j] = tmpFreq;
Vals[j] = tmpVal;
}
do
Freqs[i] = (UInt16)(Freqs[i] + Freqs[i + 1]);
while (i--);
}
else
{
i = NumItems - 1;
do
{
Freqs[i] >>= 1;
if (Freqs[i] <= Freqs[i + 1])
Freqs[i] = (UInt16)(Freqs[i + 1] + 1);
}
while (i--);
}
}
return res;
}
void CDecoder::Init()
{
m_Selector.Init(kNumSelectors);
@@ -29,156 +97,97 @@ void CDecoder::Init()
m_LenSlot.Init(kNumLenSymbols);
}
HRESULT CDecoder::CodeSpec(UInt32 curSize)
HRESULT CDecoder::CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize)
{
if (_remainLen == kLenIdNeedInit)
{
_rangeDecoder.Init();
_remainLen = 0;
}
if (curSize == 0)
return S_OK;
if (inSize < 2)
return S_FALSE;
while (_remainLen > 0 && curSize > 0)
{
_remainLen--;
Byte b = _outWindowStream.GetByte(_rep0);
_outWindowStream.PutByte(b);
curSize--;
}
CRangeDecoder rc;
rc.Stream.SetStreamAndInit(inData, inSize);
rc.Init();
while (curSize > 0)
while (outSize != 0)
{
if (_rangeDecoder.Stream.WasFinished())
if (rc.Stream.WasExtraRead())
return S_FALSE;
unsigned selector = m_Selector.Decode(&_rangeDecoder);
unsigned selector = m_Selector.Decode(&rc);
if (selector < kNumLitSelectors)
{
Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&_rangeDecoder));
_outWindowStream.PutByte(b);
curSize--;
Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&rc));
_outWindow.PutByte(b);
outSize--;
}
else
{
selector -= kNumLitSelectors;
unsigned len = selector + kMatchMinLen;
if (selector == 2)
{
unsigned lenSlot = m_LenSlot.Decode(&_rangeDecoder);
unsigned lenSlot = m_LenSlot.Decode(&rc);
if (lenSlot >= kNumSimpleLenSlots)
{
lenSlot -= 2;
int numDirectBits = (int)(lenSlot >> 2);
unsigned numDirectBits = (unsigned)(lenSlot >> 2);
len += ((4 | (lenSlot & 3)) << numDirectBits) - 2;
if (numDirectBits < 6)
len += _rangeDecoder.Stream.ReadBits(numDirectBits);
len += rc.Stream.ReadBits(numDirectBits);
}
else
len += lenSlot;
}
UInt32 rep0 = m_PosSlot[selector].Decode(&_rangeDecoder);
if (rep0 >= kNumSimplePosSlots)
UInt32 dist = m_PosSlot[selector].Decode(&rc);
if (dist >= kNumSimplePosSlots)
{
int numDirectBits = (int)((rep0 >> 1) - 1);
rep0 = ((2 | (rep0 & 1)) << numDirectBits) + _rangeDecoder.Stream.ReadBits(numDirectBits);
unsigned numDirectBits = (unsigned)((dist >> 1) - 1);
dist = ((2 | (dist & 1)) << numDirectBits) + rc.Stream.ReadBits(numDirectBits);
}
unsigned locLen = len;
if (len > curSize)
locLen = (unsigned)curSize;
if (!_outWindowStream.CopyBlock(rep0, locLen))
if (len > outSize)
locLen = (unsigned)outSize;
if (!_outWindow.CopyBlock(dist, locLen))
return S_FALSE;
curSize -= locLen;
outSize -= locLen;
len -= locLen;
if (len != 0)
{
_remainLen = (int)len;
_rep0 = rep0;
break;
}
return S_FALSE;
}
}
return _rangeDecoder.Stream.WasFinished() ? S_FALSE : S_OK;
return rc.Finish() ? S_OK : S_FALSE;
}
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
HRESULT CDecoder::Code(const Byte *inData, size_t inSize,
ISequentialOutStream *outStream, UInt32 outSize,
bool keepHistory)
{
if (outSize == NULL)
return E_INVALIDARG;
UInt64 size = *outSize;
// SetInStream(inStream);
_rangeDecoder.SetStream(inStream);
_outWindowStream.SetStream(outStream);
SetOutStreamSize(outSize);
CDecoderFlusher flusher(this);
const UInt64 start = _outWindowStream.GetProcessedSize();
for (;;)
try
{
UInt32 curSize = 1 << 18;
UInt64 rem = size - (_outWindowStream.GetProcessedSize() - start);
if (curSize > rem)
curSize = (UInt32)rem;
if (curSize == 0)
break;
RINOK(CodeSpec(curSize));
if (progress != NULL)
{
UInt64 inSize = _rangeDecoder.GetProcessedSize();
UInt64 nowPos64 = _outWindowStream.GetProcessedSize() - start;
RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
}
_outWindow.SetStream(outStream);
_outWindow.Init(keepHistory);
if (!keepHistory)
Init();
HRESULT res = CodeSpec(inData, inSize, outSize);
HRESULT res2 = _outWindow.Flush();
return res != S_OK ? res : res2;
}
flusher.NeedFlush = false;
return Flush();
}
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
catch(const CInBufferException &e) { return e.ErrorCode; }
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
catch(...) { return S_FALSE; }
}
/*
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
{
m_InStreamRef = inStream;
_rangeDecoder.SetStream(inStream);
return S_OK;
}
STDMETHODIMP CDecoder::ReleaseInStream()
{
m_InStreamRef.Release();
return S_OK;
}
*/
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
{
if (outSize == NULL)
return E_FAIL;
_remainLen = kLenIdNeedInit;
_outWindowStream.Init(_keepHistory);
if (!_keepHistory)
Init();
return S_OK;
}
HRESULT CDecoder::SetParams(int numDictBits)
HRESULT CDecoder::SetParams(unsigned numDictBits)
{
if (numDictBits > 21)
return E_INVALIDARG;
_numDictBits = numDictBits;
if (!_outWindowStream.Create((UInt32)1 << _numDictBits))
return E_OUTOFMEMORY;
if (!_rangeDecoder.Create(1 << 20))
if (!_outWindow.Create((UInt32)1 << _numDictBits))
return E_OUTOFMEMORY;
return S_OK;
}

View File

@@ -5,92 +5,94 @@
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "../Common/InBuffer.h"
#include "LzOutWindow.h"
namespace NCompress {
namespace NQuantum {
class CStreamBitDecoder
class CBitDecoder
{
UInt32 Value;
CInBuffer Stream;
bool _extra;
const Byte *_buf;
const Byte *_bufLim;
public:
bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
// void ReleaseStream() { Stream.ReleaseStream(); }
void Finish() { Value = 0x10000; }
void Init()
void SetStreamAndInit(const Byte *inData, size_t inSize)
{
Stream.Init();
_buf = inData;
_bufLim = inData + inSize;
Value = 0x10000;
_extra = false;
}
UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
bool WasFinished() const { return Stream.WasFinished(); }
bool WasExtraRead() const { return _extra; }
bool WasFinishedOK() const
{
return !_extra && _buf == _bufLim;
}
UInt32 ReadBit()
{
if (Value >= 0x10000)
Value = 0x100 | Stream.ReadByte();
{
Byte b;
if (_buf >= _bufLim)
{
b = 0xFF;
_extra = true;
}
else
b = *_buf++;
Value = 0x100 | b;
}
UInt32 res = (Value >> 7) & 1;
Value <<= 1;
return res;
}
UInt32 ReadBits(int numBits) // numBits > 0
UInt32 ReadStart16Bits()
{
// we use check for extra read in another code.
UInt32 val = ((UInt32)*_buf << 8) | _buf[1];
_buf += 2;
return val;
}
UInt32 ReadBits(unsigned numBits) // numBits > 0
{
UInt32 res = 0;
do
res = (res << 1) | ReadBit();
while (--numBits != 0);
while (--numBits);
return res;
}
};
const unsigned kNumLitSelectorBits = 2;
const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits);
const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits);
const unsigned kNumMatchSelectors = 3;
const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors;
const unsigned kNumSymbolsMax = kNumLitSymbols; // 64
namespace NRangeCoder {
class CDecoder
class CRangeDecoder
{
UInt32 Low;
UInt32 Range;
UInt32 Code;
public:
CStreamBitDecoder Stream;
bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); }
void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); }
// void ReleaseStream() { Stream.ReleaseStream(); }
CBitDecoder Stream;
void Init()
{
Stream.Init();
Low = 0;
Range = 0x10000;
Code = Stream.ReadBits(16);
Code = Stream.ReadStart16Bits();
}
void Finish()
bool Finish()
{
// we need these extra two Bit_reads
Stream.ReadBit();
Stream.ReadBit();
Stream.Finish();
// do all streams use these two bits at end?
if (Stream.ReadBit() != 0) return false;
if (Stream.ReadBit() != 0) return false;
return Stream.WasFinishedOK();
}
UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
UInt32 GetThreshold(UInt32 total) const
{
return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required;
@@ -119,148 +121,52 @@ public:
}
};
const UInt16 kUpdateStep = 8;
const UInt16 kFreqSumMax = 3800;
const UInt16 kReorderCountStart = 4;
const UInt16 kReorderCount = 50;
const unsigned kNumLitSelectorBits = 2;
const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits);
const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits);
const unsigned kNumMatchSelectors = 3;
const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors;
const unsigned kNumSymbolsMax = kNumLitSymbols; // 64
class CModelDecoder
{
unsigned NumItems;
unsigned ReorderCount;
UInt16 Freqs[kNumSymbolsMax + 1];
Byte Values[kNumSymbolsMax];
Byte Vals[kNumSymbolsMax];
public:
void Init(unsigned numItems)
{
NumItems = numItems;
ReorderCount = kReorderCountStart;
for (unsigned i = 0; i < numItems; i++)
{
Freqs[i] = (UInt16)(numItems - i);
Values[i] = (Byte)i;
}
Freqs[numItems] = 0;
}
unsigned Decode(CDecoder *rangeDecoder)
{
UInt32 threshold = rangeDecoder->GetThreshold(Freqs[0]);
unsigned i;
for (i = 1; Freqs[i] > threshold; i++);
rangeDecoder->Decode(Freqs[i], Freqs[i - 1], Freqs[0]);
unsigned res = Values[--i];
do
Freqs[i] += kUpdateStep;
while (i-- != 0);
if (Freqs[0] > kFreqSumMax)
{
if (--ReorderCount == 0)
{
ReorderCount = kReorderCount;
for (i = 0; i < NumItems; i++)
Freqs[i] = (UInt16)(((Freqs[i] - Freqs[i + 1]) + 1) >> 1);
for (i = 0; i < NumItems - 1; i++)
for (unsigned j = i + 1; j < NumItems; j++)
if (Freqs[i] < Freqs[j])
{
UInt16 tmpFreq = Freqs[i];
Byte tmpVal = Values[i];
Freqs[i] = Freqs[j];
Values[i] = Values[j];
Freqs[j] = tmpFreq;
Values[j] = tmpVal;
}
do
Freqs[i] = (UInt16)(Freqs[i] + Freqs[i + 1]);
while (i-- != 0);
}
else
{
i = NumItems - 1;
do
{
Freqs[i] >>= 1;
if (Freqs[i] <= Freqs[i + 1])
Freqs[i] = (UInt16)(Freqs[i + 1] + 1);
}
while (i-- != 0);
}
}
return res;
}
void Init(unsigned numItems);
unsigned Decode(CRangeDecoder *rc);
};
}
class CDecoder:
public ICompressCoder,
// public ICompressSetInStream,
// public ICompressSetOutStreamSize,
public IUnknown,
public CMyUnknownImp
{
CLzOutWindow _outWindowStream;
// CMyComPtr<ISequentialInStream> m_InStreamRef;
NRangeCoder::CDecoder _rangeDecoder;
CLzOutWindow _outWindow;
unsigned _numDictBits;
UInt64 _outSize;
int _remainLen; // -1 means end of stream. // -2 means need Init
UInt32 _rep0;
CModelDecoder m_Selector;
CModelDecoder m_Literals[kNumLitSelectors];
CModelDecoder m_PosSlot[kNumMatchSelectors];
CModelDecoder m_LenSlot;
int _numDictBits;
bool _keepHistory;
NRangeCoder::CModelDecoder m_Selector;
NRangeCoder::CModelDecoder m_Literals[kNumLitSelectors];
NRangeCoder::CModelDecoder m_PosSlot[kNumMatchSelectors];
NRangeCoder::CModelDecoder m_LenSlot;
void Init();
HRESULT CodeSpec(UInt32 size);
HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize);
public:
MY_UNKNOWN_IMP
/*
MY_UNKNOWN_IMP2(
ICompressSetInStream,
ICompressSetOutStreamSize)
void ReleaseStreams()
{
_outWindowStream.ReleaseStream();
ReleaseInStream();
}
*/
HRESULT Code(const Byte *inData, size_t inSize,
ISequentialOutStream *outStream, UInt32 outSize,
bool keepHistory);
class CDecoderFlusher
{
CDecoder *_decoder;
public:
bool NeedFlush;
CDecoderFlusher(CDecoder *decoder): _decoder(decoder), NeedFlush(true) {}
~CDecoderFlusher()
{
if (NeedFlush)
_decoder->Flush();
// _decoder->ReleaseStreams();
}
};
HRESULT Flush() { return _outWindowStream.Flush(); }
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
HRESULT SetParams(unsigned numDictBits);
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
// STDMETHOD(SetInStream)(ISequentialInStream *inStream);
// STDMETHOD(ReleaseInStream)();
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
HRESULT SetParams(int numDictBits);
void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
CDecoder(): _keepHistory(false) {}
CDecoder(): _numDictBits(0) {}
virtual ~CDecoder() {}
};

View File

@@ -122,21 +122,21 @@ bool CDecoder::ReadTables(void)
unsigned i;
for (i = 0; i < kLevelTableSize; i++)
levelLevels[i] = (Byte)ReadBits(4);
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
RIF(m_LevelDecoder.Build(levelLevels));
i = 0;
while (i < numLevels)
{
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
if (number < kTableDirectLevels)
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
if (sym < kTableDirectLevels)
{
newLevels[i] = (Byte)((number + m_LastLevels[i]) & kLevelMask);
newLevels[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask);
i++;
}
else
{
if (number == kTableLevelRepNumber)
if (sym == kTableLevelRepNumber)
{
unsigned t = ReadBits(2) + 3;
for (unsigned reps = t; reps > 0 && i < numLevels; reps--, i++)
@@ -145,9 +145,9 @@ bool CDecoder::ReadTables(void)
else
{
unsigned num;
if (number == kTableLevel0Number)
if (sym == kTableLevel0Number)
num = ReadBits(3) + 3;
else if (number == kTableLevel0Number2)
else if (sym == kTableLevel0Number2)
num = ReadBits(7) + 11;
else
return false;
@@ -160,13 +160,13 @@ bool CDecoder::ReadTables(void)
if (m_AudioMode)
for (i = 0; i < m_NumChannels; i++)
{
RIF(m_MMDecoders[i].SetCodeLengths(&newLevels[i * kMMTableSize]));
RIF(m_MMDecoders[i].Build(&newLevels[i * kMMTableSize]));
}
else
{
RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
RIF(m_MainDecoder.Build(&newLevels[0]));
RIF(m_DistDecoder.Build(&newLevels[kMainTableSize]));
RIF(m_LenDecoder.Build(&newLevels[kMainTableSize + kDistTableSize]));
}
memcpy(m_LastLevels, newLevels, kMaxTableSize);
@@ -182,7 +182,7 @@ bool CDecoder::ReadLastTables()
// if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
if (m_AudioMode)
{
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
if (symbol == 256)
return ReadTables();
if (symbol >= kMMTableSize)
@@ -190,10 +190,10 @@ bool CDecoder::ReadLastTables()
}
else
{
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
if (number == kReadTableNumber)
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
if (sym == kReadTableNumber)
return ReadTables();
if (number >= kMainTableSize)
if (sym >= kMainTableSize)
return false;
}
return true;
@@ -216,7 +216,7 @@ bool CDecoder::DecodeMm(UInt32 pos)
{
while (pos-- > 0)
{
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].DecodeSymbol(&m_InBitStream);
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
if (symbol == 256)
return true;
if (symbol >= kMMTableSize)
@@ -238,23 +238,23 @@ bool CDecoder::DecodeLz(Int32 pos)
{
while (pos > 0)
{
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
UInt32 length, distance;
if (number < 256)
if (sym < 256)
{
m_OutWindowStream.PutByte(Byte(number));
m_OutWindowStream.PutByte(Byte(sym));
pos--;
continue;
}
else if (number >= kMatchNumber)
else if (sym >= kMatchNumber)
{
number -= kMatchNumber;
length = kNormalMatchMinLen + UInt32(kLenStart[number]) +
m_InBitStream.ReadBits(kLenDirectBits[number]);
number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
if (number >= kDistTableSize)
sym -= kMatchNumber;
length = kNormalMatchMinLen + UInt32(kLenStart[sym]) +
m_InBitStream.ReadBits(kLenDirectBits[sym]);
sym = m_DistDecoder.Decode(&m_InBitStream);
if (sym >= kDistTableSize)
return false;
distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);
distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
if (distance >= kDistLimit3)
{
length += 2 - ((distance - kDistLimit4) >> 31);
@@ -263,20 +263,20 @@ bool CDecoder::DecodeLz(Int32 pos)
// length++;
}
}
else if (number == kRepBothNumber)
else if (sym == kRepBothNumber)
{
length = m_LastLength;
if (length == 0)
return false;
distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
}
else if (number < kLen2Number)
else if (sym < kLen2Number)
{
distance = m_RepDists[(m_RepDistPtr - (number - kRepNumber + 1)) & 3];
number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
if (number >= kLenTableSize)
distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3];
sym = m_LenDecoder.Decode(&m_InBitStream);
if (sym >= kLenTableSize)
return false;
length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
length = 2 + kLenStart[sym] + m_InBitStream.ReadBits(kLenDirectBits[sym]);
if (distance >= kDistLimit2)
{
length++;
@@ -289,14 +289,14 @@ bool CDecoder::DecodeLz(Int32 pos)
}
}
}
else if (number < kReadTableNumber)
else if (sym < kReadTableNumber)
{
number -= kLen2Number;
distance = kLen2DistStarts[number] +
m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
sym -= kLen2Number;
distance = kLen2DistStarts[sym] +
m_InBitStream.ReadBits(kLen2DistDirectBits[sym]);
length = 2;
}
else if (number == kReadTableNumber)
else if (sym == kReadTableNumber)
return true;
else
return false;

View File

@@ -568,26 +568,26 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
}
levelLevels[i] = (Byte)length;
}
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
RIF(m_LevelDecoder.Build(levelLevels));
i = 0;
while (i < kTablesSizesSum)
{
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number < 16)
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym < 16)
{
newLevels[i] = Byte((number + m_LastLevels[i]) & 15);
newLevels[i] = Byte((sym + m_LastLevels[i]) & 15);
i++;
}
else if (number > kLevelTableSize)
else if (sym > kLevelTableSize)
return S_FALSE;
else
{
int num;
if (((number - 16) & 1) == 0)
if (((sym - 16) & 1) == 0)
num = ReadBits(3) + 3;
else
num = ReadBits(7) + 11;
if (number < 18)
if (sym < 18)
{
if (i == 0)
return S_FALSE;
@@ -612,10 +612,10 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
}
*/
RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
RIF(m_MainDecoder.Build(&newLevels[0]));
RIF(m_DistDecoder.Build(&newLevels[kMainTableSize]));
RIF(m_AlignDecoder.Build(&newLevels[kMainTableSize + kDistTableSize]));
RIF(m_LenDecoder.Build(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
memcpy(m_LastLevels, newLevels, kTablesSizesSum);
return S_OK;
@@ -687,38 +687,38 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
if (InputEofError_Fast())
return S_FALSE;
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number < 256)
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym < 256)
{
PutByte((Byte)number);
PutByte((Byte)sym);
continue;
}
else if (number == kSymbolReadTable)
else if (sym == kSymbolReadTable)
{
RINOK(ReadEndOfBlock(keepDecompressing));
break;
}
else if (number == 257)
else if (sym == 257)
{
if (!ReadVmCodeLZ())
return S_FALSE;
continue;
}
else if (number == 258)
else if (sym == 258)
{
if (length == 0)
return S_FALSE;
}
else if (number < kSymbolRep + 4)
else if (sym < kSymbolRep + 4)
{
if (number != kSymbolRep)
if (sym != kSymbolRep)
{
UInt32 distance;
if (number == kSymbolRep + 1)
if (sym == kSymbolRep + 1)
distance = rep1;
else
{
if (number == kSymbolRep + 2)
if (sym == kSymbolRep + 2)
distance = rep2;
else
{
@@ -731,32 +731,32 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
rep0 = distance;
}
UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number >= kLenTableSize)
UInt32 sym = m_LenDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym >= kLenTableSize)
return S_FALSE;
length = 2 + kLenStart[number] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[number]);
length = 2 + kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]);
}
else
{
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
if (number < 271)
if (sym < 271)
{
number -= 263;
rep0 = kLen2DistStarts[number] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[number]);
sym -= 263;
rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[sym]);
length = 2;
}
else if (number < 299)
else if (sym < 299)
{
number -= 271;
length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[number]);
UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number >= kDistTableSize)
sym -= 271;
length = kNormalMatchMinLen + (UInt32)kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]);
UInt32 sym = m_DistDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym >= kDistTableSize)
return S_FALSE;
rep0 = kDistStart[number];
int numBits = kDistDirectBits[number];
if (number >= (kNumAlignBits * 2) + 2)
rep0 = kDistStart[sym];
int numBits = kDistDirectBits[sym];
if (sym >= (kNumAlignBits * 2) + 2)
{
if (numBits > kNumAlignBits)
rep0 += (m_InBitStream.BitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
@@ -767,13 +767,13 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
}
else
{
UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream.BitDecoder);
if (number < (1 << kNumAlignBits))
UInt32 sym = m_AlignDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym < (1 << kNumAlignBits))
{
rep0 += number;
PrevAlignBits = number;
rep0 += sym;
PrevAlignBits = sym;
}
else if (number == (1 << kNumAlignBits))
else if (sym == (1 << kNumAlignBits))
{
PrevAlignCount = kNumAlignReps;
rep0 += PrevAlignBits;

View File

@@ -304,6 +304,7 @@ HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream)
// if (f.Size > ((UInt32)1 << 16)) _unsupportedFilter = true;
f.Type = (Byte)_bitStream.ReadBits9fix(3);
f.Channels = 0;
if (f.Type == FILTER_DELTA)
f.Channels = (Byte)(_bitStream.ReadBits9fix(5) + 1);
f.Start = _lzSize + blockStart;
@@ -408,7 +409,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
if (_bitStream.IsBlockOverRead())
return S_FALSE;
RIF(m_LevelDecoder.SetCodeLengths(lens2));
RIF(m_LevelDecoder.Build(lens2));
}
Byte lens[kTablesSizesSum];
@@ -424,7 +425,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
return S_FALSE;
}
UInt32 sym = m_LevelDecoder.DecodeSymbol(&_bitStream);
UInt32 sym = m_LevelDecoder.Decode(&_bitStream);
if (sym < 16)
lens[i++] = (Byte)sym;
@@ -466,10 +467,10 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
if (_bitStream.InputEofError())
return S_FALSE;
RIF(m_MainDecoder.SetCodeLengths(&lens[0]));
RIF(m_DistDecoder.SetCodeLengths(&lens[kMainTableSize]));
RIF(m_AlignDecoder.SetCodeLengths(&lens[kMainTableSize + kDistTableSize]));
RIF(m_LenDecoder.SetCodeLengths(&lens[kMainTableSize + kDistTableSize + kAlignTableSize]));
RIF(m_MainDecoder.Build(&lens[0]));
RIF(m_DistDecoder.Build(&lens[kMainTableSize]));
RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize]));
RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize]));
_useAlignBits = false;
// _useAlignBits = true;
@@ -601,7 +602,7 @@ HRESULT CDecoder::DecodeLZ()
}
}
UInt32 sym = m_MainDecoder.DecodeSymbol(&_bitStream);
UInt32 sym = m_MainDecoder.Decode(&_bitStream);
if (sym < 256)
{
@@ -638,7 +639,7 @@ HRESULT CDecoder::DecodeLZ()
rep0 = dist;
}
UInt32 sym = m_LenDecoder.DecodeSymbol(&_bitStream);
UInt32 sym = m_LenDecoder.Decode(&_bitStream);
if (sym >= kLenTableSize)
break; // return S_FALSE;
len = SlotToLen(_bitStream, sym);
@@ -669,7 +670,7 @@ HRESULT CDecoder::DecodeLZ()
_reps[1] = rep0;
len = SlotToLen(_bitStream, sym - (kSymbolRep + kNumReps));
rep0 = m_DistDecoder.DecodeSymbol(&_bitStream);
rep0 = m_DistDecoder.Decode(&_bitStream);
if (rep0 >= 4)
{
@@ -690,7 +691,7 @@ HRESULT CDecoder::DecodeLZ()
{
// if (numBits > kNumAlignBits)
rep0 += (_bitStream.ReadBits32(numBits - kNumAlignBits) << kNumAlignBits);
UInt32 a = m_AlignDecoder.DecodeSymbol(&_bitStream);
UInt32 a = m_AlignDecoder.Decode(&_bitStream);
if (a >= kAlignTableSize)
break; // return S_FALSE;
rep0 += a;

View File

@@ -0,0 +1,129 @@
// XpressDecoder.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../C/CpuArch.h"
#include "HuffmanDecoder.h"
namespace NCompress {
namespace NXpress {
struct CBitStream
{
UInt32 Value;
unsigned BitPos;
UInt32 GetValue(unsigned numBits) const
{
return (Value >> (BitPos - numBits)) & ((1 << numBits) - 1);
}
void MovePos(unsigned numBits)
{
BitPos -= numBits;
}
};
#define BIT_STREAM_NORMALIZE \
if (bs.BitPos < 16) { \
if (in >= lim) return S_FALSE; \
bs.Value = (bs.Value << 16) | GetUi16(in); \
in += 2; bs.BitPos += 16; }
const unsigned kNumHuffBits = 15;
const unsigned kNumLenSlots = 16;
const unsigned kNumPosSlots = 16;
const unsigned kNumSyms = 256 + kNumPosSlots * kNumLenSlots;
HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize)
{
NCompress::NHuffman::CDecoder<kNumHuffBits, kNumSyms> huff;
if (inSize < kNumSyms / 2 + 4)
return S_FALSE;
{
Byte levels[kNumSyms];
for (unsigned i = 0; i < kNumSyms / 2; i++)
{
Byte b = in[i];
levels[i * 2] = (Byte)(b & 0xF);
levels[i * 2 + 1] = (Byte)(b >> 4);
}
if (!huff.BuildFull(levels))
return S_FALSE;
}
CBitStream bs;
const Byte *lim = in + inSize - 1;
in += kNumSyms / 2;
bs.Value = (GetUi16(in) << 16) | GetUi16(in + 2);
in += 4;
bs.BitPos = 32;
size_t pos = 0;
for (;;)
{
// printf("\n%d", pos);
UInt32 sym = huff.DecodeFull(&bs);
// printf(" sym = %d", sym);
BIT_STREAM_NORMALIZE
if (pos >= outSize)
return (sym == 256 && in == lim + 1) ? S_OK : S_FALSE;
if (sym < 256)
out[pos++] = (Byte)sym;
else
{
sym -= 256;
UInt32 dist = sym / kNumLenSlots;
UInt32 len = sym & (kNumLenSlots - 1);
if (len == kNumLenSlots - 1)
{
if (in > lim)
return S_FALSE;
len = *in++;
if (len == 0xFF)
{
if (in >= lim)
return S_FALSE;
len = GetUi16(in);
in += 2;
}
else
len += kNumLenSlots - 1;
}
bs.BitPos -= dist;
dist = (UInt32)1 << dist;
dist += ((bs.Value >> bs.BitPos) & (dist - 1));
BIT_STREAM_NORMALIZE
if (len > outSize - pos)
return S_FALSE;
if (dist > pos)
return S_FALSE;
Byte *dest = out + pos;
const Byte *src = dest - dist;
pos += len + 3;
len += 1;
*dest++ = *src++;
*dest++ = *src++;
do
*dest++ = *src++;
while (--len);
}
}
}
}}

View File

@@ -0,0 +1,13 @@
// XpressDecoder.h
#ifndef __XPRESS_DECODER_H
#define __XPRESS_DECODER_H
namespace NCompress {
namespace NXpress {
HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize);
}}
#endif