mirror of
https://github.com/Xevion/easy7zip.git
synced 2026-02-01 02:24:22 -06:00
Initialer Commit
This commit is contained in:
@@ -0,0 +1,529 @@
|
||||
// LzxDecoder.cpp
|
||||
|
||||
#include "StdAfx.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 {
|
||||
|
||||
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):
|
||||
_win(NULL),
|
||||
_keepHistory(false),
|
||||
_skipByte(false),
|
||||
_wimMode(wimMode),
|
||||
_numDictBits(15),
|
||||
_unpackBlockSize(0),
|
||||
_x86_buf(NULL),
|
||||
_x86_translationSize(0),
|
||||
KeepHistoryForNext(true),
|
||||
NeedAlloc(true),
|
||||
_unpackedData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
if (NeedAlloc)
|
||||
::MidFree(_win);
|
||||
::MidFree(_x86_buf);
|
||||
}
|
||||
|
||||
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 *levels, unsigned numSymbols)
|
||||
{
|
||||
{
|
||||
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)
|
||||
{
|
||||
int delta = (int)levels[i] - (int)sym;
|
||||
delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0;
|
||||
levels[i++] = (Byte)delta;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned num;
|
||||
Byte symbol;
|
||||
|
||||
if (sym < kLevelSym_Same)
|
||||
{
|
||||
sym -= kLevelSym_Zero1;
|
||||
num = kLevelSym_Zero1_Start + ((unsigned)sym << kLevelSym_Zero1_NumBits) +
|
||||
(unsigned)ReadBits(kLevelSym_Zero1_NumBits + sym);
|
||||
symbol = 0;
|
||||
}
|
||||
else if (sym == kLevelSym_Same)
|
||||
{
|
||||
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)
|
||||
{
|
||||
{
|
||||
if (_skipByte)
|
||||
{
|
||||
if (_bitStream.DirectReadByte() != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
_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)
|
||||
{
|
||||
_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;
|
||||
}
|
||||
|
||||
_numAlignBits = 64;
|
||||
|
||||
if (blockType == kBlockType_Aligned)
|
||||
{
|
||||
Byte levels[kAlignTableSize];
|
||||
_numAlignBits = kNumAlignBits;
|
||||
for (unsigned i = 0; i < kAlignTableSize; i++)
|
||||
levels[i] = (Byte)ReadBits(kNumAlignLevelBits);
|
||||
RIF(_alignDecoder.Build(levels));
|
||||
}
|
||||
}
|
||||
|
||||
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 (!_keepHistory || !_isUncompressedBlock)
|
||||
_bitStream.NormalizeBig();
|
||||
|
||||
if (!_keepHistory)
|
||||
{
|
||||
_skipByte = false;
|
||||
_unpackBlockSize = 0;
|
||||
|
||||
memset(_mainLevels, 0, kMainTableSize);
|
||||
memset(_lenLevels, 0, kNumLenSymbols);
|
||||
|
||||
{
|
||||
_x86_translationSize = 12000000;
|
||||
if (!_wimMode)
|
||||
{
|
||||
_x86_translationSize = 0;
|
||||
if (ReadBits(1) != 0)
|
||||
{
|
||||
UInt32 v = ReadBits(16) << 16;
|
||||
v |= ReadBits(16);
|
||||
_x86_translationSize = v;
|
||||
}
|
||||
}
|
||||
|
||||
_x86_processedSize = 0;
|
||||
}
|
||||
|
||||
_reps[0] = 1;
|
||||
_reps[1] = 1;
|
||||
_reps[2] = 1;
|
||||
}
|
||||
|
||||
while (curSize > 0)
|
||||
{
|
||||
if (_bitStream.WasExtraReadError_Fast())
|
||||
return S_FALSE;
|
||||
|
||||
if (_unpackBlockSize == 0)
|
||||
{
|
||||
if (!ReadTables())
|
||||
return S_FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
UInt32 next = _unpackBlockSize;
|
||||
if (next > curSize)
|
||||
next = curSize;
|
||||
|
||||
if (_isUncompressedBlock)
|
||||
{
|
||||
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())
|
||||
{
|
||||
_skipByte = false;
|
||||
if (_bitStream.DirectReadByte() != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
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 = _lenDecoder.Decode(&_bitStream);
|
||||
if (lenTemp >= kNumLenSymbols)
|
||||
return S_FALSE;
|
||||
len = kMatchMinLen + kNumLenSlots - 1 + lenTemp;
|
||||
}
|
||||
|
||||
UInt32 dist;
|
||||
|
||||
if (posSlot < kNumReps)
|
||||
{
|
||||
dist = _reps[posSlot];
|
||||
_reps[posSlot] = _reps[0];
|
||||
_reps[0] = dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned numDirectBits;
|
||||
|
||||
if (posSlot < kNumPowerPosSlots)
|
||||
{
|
||||
numDirectBits = (unsigned)(posSlot >> 1) - 1;
|
||||
dist = ((2 | (posSlot & 1)) << numDirectBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
numDirectBits = kNumLinearPosSlotBits;
|
||||
dist = ((posSlot - 0x22) << kNumLinearPosSlotBits);
|
||||
}
|
||||
|
||||
if (numDirectBits >= _numAlignBits)
|
||||
{
|
||||
dist += (_bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits);
|
||||
UInt32 alignTemp = _alignDecoder.Decode(&_bitStream);
|
||||
if (alignTemp >= kAlignTableSize)
|
||||
return S_FALSE;
|
||||
dist += alignTemp;
|
||||
}
|
||||
else
|
||||
dist += _bitStream.ReadBitsBig(numDirectBits);
|
||||
|
||||
dist -= kNumReps - 1;
|
||||
_reps[2] = _reps[1];
|
||||
_reps[1] = _reps[0];
|
||||
_reps[0] = dist;
|
||||
}
|
||||
|
||||
if (len > next)
|
||||
return S_FALSE;
|
||||
|
||||
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)
|
||||
{
|
||||
_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::Code(const Byte *inData, size_t inSize, UInt32 outSize)
|
||||
{
|
||||
if (!_keepHistory)
|
||||
{
|
||||
_pos = 0;
|
||||
_overDict = false;
|
||||
}
|
||||
else if (_pos == _winSize)
|
||||
{
|
||||
_pos = 0;
|
||||
_overDict = true;
|
||||
}
|
||||
|
||||
_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)
|
||||
{
|
||||
::MidFree(_win);
|
||||
_winSize = 0;
|
||||
_win = (Byte *)::MidAlloc(newWinSize);
|
||||
if (!_win)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
_winSize = (UInt32)newWinSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
Reference in New Issue
Block a user