mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-10 00:07:06 -06:00
4.44 beta
This commit is contained in:
committed by
Kornel Lesiński
parent
804edc5756
commit
d9666cf046
173
CPP/7zip/Compress/Quantum/QuantumDecoder.cpp
Executable file
173
CPP/7zip/Compress/Quantum/QuantumDecoder.cpp
Executable file
@@ -0,0 +1,173 @@
|
||||
// QuantumDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "QuantumDecoder.h"
|
||||
#include "../../../Common/Defs.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NQuantum {
|
||||
|
||||
const UInt32 kDictionarySizeMax = (1 << 21);
|
||||
|
||||
const int kLenIdNeedInit = -2;
|
||||
|
||||
void CDecoder::Init()
|
||||
{
|
||||
m_Selector.Init(kNumSelectors);
|
||||
for (unsigned int i = 0; i < kNumLitSelectors; i++)
|
||||
m_Literals[i].Init(kNumLitSymbols);
|
||||
unsigned int numItems = _numDictBits << 1;
|
||||
m_PosSlot[0].Init(MyMin(numItems, kNumLen3PosSymbolsMax));
|
||||
m_PosSlot[1].Init(MyMin(numItems, kNumLen4PosSymbolsMax));
|
||||
m_PosSlot[2].Init(MyMin(numItems, kNumLen5PosSymbolsMax));
|
||||
m_LenSlot.Init(kNumLenSymbols);
|
||||
}
|
||||
|
||||
HRESULT CDecoder::CodeSpec(UInt32 curSize)
|
||||
{
|
||||
if (_remainLen == kLenIdNeedInit)
|
||||
{
|
||||
if (!_keepHistory)
|
||||
{
|
||||
if (!_outWindowStream.Create(_dictionarySize))
|
||||
return E_OUTOFMEMORY;
|
||||
Init();
|
||||
}
|
||||
if (!_rangeDecoder.Create(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
_rangeDecoder.Init();
|
||||
_remainLen = 0;
|
||||
}
|
||||
if (curSize == 0)
|
||||
return S_OK;
|
||||
|
||||
while(_remainLen > 0 && curSize > 0)
|
||||
{
|
||||
_remainLen--;
|
||||
Byte b = _outWindowStream.GetByte(_rep0);
|
||||
_outWindowStream.PutByte(b);
|
||||
curSize--;
|
||||
}
|
||||
|
||||
while(curSize > 0)
|
||||
{
|
||||
if (_rangeDecoder.Stream.WasFinished())
|
||||
return S_FALSE;
|
||||
|
||||
unsigned int selector = m_Selector.Decode(&_rangeDecoder);
|
||||
if (selector < kNumLitSelectors)
|
||||
{
|
||||
Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&_rangeDecoder));
|
||||
_outWindowStream.PutByte(b);
|
||||
curSize--;
|
||||
}
|
||||
else
|
||||
{
|
||||
selector -= kNumLitSelectors;
|
||||
unsigned int len = selector + kMatchMinLen;
|
||||
if (selector == 2)
|
||||
{
|
||||
unsigned int lenSlot = m_LenSlot.Decode(&_rangeDecoder);;
|
||||
if (lenSlot >= kNumSimpleLenSlots)
|
||||
{
|
||||
lenSlot -= 2;
|
||||
int numDirectBits = (int)(lenSlot >> 2);
|
||||
len += ((4 | (lenSlot & 3)) << numDirectBits) - 2;
|
||||
if (numDirectBits < 6)
|
||||
len += _rangeDecoder.Stream.ReadBits(numDirectBits);
|
||||
}
|
||||
else
|
||||
len += lenSlot;
|
||||
}
|
||||
UInt32 rep0 = m_PosSlot[selector].Decode(&_rangeDecoder);;
|
||||
if (rep0 >= kNumSimplePosSlots)
|
||||
{
|
||||
int numDirectBits = (int)((rep0 >> 1) - 1);
|
||||
rep0 = ((2 | (rep0 & 1)) << numDirectBits) + _rangeDecoder.Stream.ReadBits(numDirectBits);
|
||||
}
|
||||
unsigned int locLen = len;
|
||||
if (len > curSize)
|
||||
locLen = (unsigned int)curSize;
|
||||
if (!_outWindowStream.CopyBlock(rep0, locLen))
|
||||
return S_FALSE;
|
||||
curSize -= locLen;
|
||||
len -= locLen;
|
||||
if (len != 0)
|
||||
{
|
||||
_remainLen = (int)len;
|
||||
_rep0 = rep0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return _rangeDecoder.Stream.WasFinished() ? S_FALSE : S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream,
|
||||
ISequentialOutStream *outStream,
|
||||
const UInt64 *, const UInt64 *outSize,
|
||||
ICompressProgressInfo *progress)
|
||||
{
|
||||
if (outSize == NULL)
|
||||
return E_INVALIDARG;
|
||||
UInt64 size = *outSize;
|
||||
|
||||
SetInStream(inStream);
|
||||
_outWindowStream.SetStream(outStream);
|
||||
SetOutStreamSize(outSize);
|
||||
CDecoderFlusher flusher(this);
|
||||
|
||||
const UInt64 start = _outWindowStream.GetProcessedSize();
|
||||
for (;;)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
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(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
|
||||
{
|
||||
_rangeDecoder.SetStream(inStream);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::ReleaseInStream()
|
||||
{
|
||||
_rangeDecoder.ReleaseStream();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
||||
{
|
||||
if (outSize == NULL)
|
||||
return E_FAIL;
|
||||
_remainLen = kLenIdNeedInit;
|
||||
_outWindowStream.Init(_keepHistory);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
287
CPP/7zip/Compress/Quantum/QuantumDecoder.h
Executable file
287
CPP/7zip/Compress/Quantum/QuantumDecoder.h
Executable file
@@ -0,0 +1,287 @@
|
||||
// QuantumDecoder.h
|
||||
|
||||
#ifndef __QUANTUM_DECODER_H
|
||||
#define __QUANTUM_DECODER_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
|
||||
#include "../../Common/InBuffer.h"
|
||||
#include "../../ICoder.h"
|
||||
#include "../LZ/LZOutWindow.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NQuantum {
|
||||
|
||||
class CStreamBitDecoder
|
||||
{
|
||||
UInt32 m_Value;
|
||||
CInBuffer m_Stream;
|
||||
public:
|
||||
bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); }
|
||||
void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream);}
|
||||
void ReleaseStream() { m_Stream.ReleaseStream();}
|
||||
|
||||
void Finish() { m_Value = 0x10000; }
|
||||
|
||||
void Init()
|
||||
{
|
||||
m_Stream.Init();
|
||||
m_Value = 0x10000;
|
||||
}
|
||||
|
||||
UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize(); }
|
||||
bool WasFinished() const { return m_Stream.WasFinished(); };
|
||||
|
||||
UInt32 ReadBit()
|
||||
{
|
||||
if (m_Value >= 0x10000)
|
||||
m_Value = 0x100 | m_Stream.ReadByte();
|
||||
UInt32 res = (m_Value >> 7) & 1;
|
||||
m_Value <<= 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
UInt32 ReadBits(int numBits) // numBits > 0
|
||||
{
|
||||
UInt32 res = 0;
|
||||
do
|
||||
res = (res << 1) | ReadBit();
|
||||
while(--numBits != 0);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
const int kNumLitSelectorBits = 2;
|
||||
const unsigned int kNumLitSelectors = (1 << kNumLitSelectorBits);
|
||||
const unsigned int kNumLitSymbols = 1 << (8 - kNumLitSelectorBits);
|
||||
const unsigned int kNumMatchSelectors = 3;
|
||||
const unsigned int kNumSelectors = kNumLitSelectors + kNumMatchSelectors;
|
||||
const unsigned int kNumLen3PosSymbolsMax = 24;
|
||||
const unsigned int kNumLen4PosSymbolsMax = 36;
|
||||
const unsigned int kNumLen5PosSymbolsMax = 42;
|
||||
const unsigned int kNumLenSymbols = 27;
|
||||
|
||||
const unsigned int kNumSymbolsMax = kNumLitSymbols; // 64
|
||||
|
||||
const unsigned int kMatchMinLen = 3;
|
||||
const unsigned int kNumSimplePosSlots = 4;
|
||||
const unsigned int kNumSimpleLenSlots = 6;
|
||||
|
||||
namespace NRangeCoder {
|
||||
|
||||
class CDecoder
|
||||
{
|
||||
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(); }
|
||||
|
||||
void Init()
|
||||
{
|
||||
Stream.Init();
|
||||
Low = 0;
|
||||
Range = 0x10000;
|
||||
Code = Stream.ReadBits(16);
|
||||
}
|
||||
|
||||
void Finish()
|
||||
{
|
||||
// we need these extra two Bit_reads
|
||||
Stream.ReadBit();
|
||||
Stream.ReadBit();
|
||||
Stream.Finish();
|
||||
}
|
||||
|
||||
UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
|
||||
|
||||
UInt32 GetThreshold(UInt32 total) const
|
||||
{
|
||||
return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required;
|
||||
}
|
||||
|
||||
void Decode(UInt32 start, UInt32 end, UInt32 total)
|
||||
{
|
||||
UInt32 high = Low + end * Range / total - 1;
|
||||
UInt32 offset = start * Range / total;
|
||||
Code -= offset;
|
||||
Low += offset;
|
||||
for (;;)
|
||||
{
|
||||
if ((Low & 0x8000) != (high & 0x8000))
|
||||
{
|
||||
if ((Low & 0x4000) == 0 || (high & 0x4000) != 0)
|
||||
break;
|
||||
Low &= 0x3FFF;
|
||||
high |= 0x4000;
|
||||
}
|
||||
Low = (Low << 1) & 0xFFFF;
|
||||
high = ((high << 1) | 1) & 0xFFFF;
|
||||
Code = ((Code << 1) | Stream.ReadBit());
|
||||
}
|
||||
Range = high - Low + 1;
|
||||
}
|
||||
};
|
||||
|
||||
const UInt16 kUpdateStep = 8;
|
||||
const UInt16 kFreqSumMax = 3800;
|
||||
const UInt16 kReorderCountStart = 4;
|
||||
const UInt16 kReorderCount = 50;
|
||||
|
||||
class CModelDecoder
|
||||
{
|
||||
unsigned int NumItems;
|
||||
unsigned int ReorderCount;
|
||||
UInt16 Freqs[kNumSymbolsMax + 1];
|
||||
Byte Values[kNumSymbolsMax];
|
||||
public:
|
||||
void Init(unsigned int numItems)
|
||||
{
|
||||
NumItems = numItems;
|
||||
ReorderCount = kReorderCountStart;
|
||||
for(unsigned int i = 0; i < numItems; i++)
|
||||
{
|
||||
Freqs[i] = (UInt16)(numItems - i);
|
||||
Values[i] = (Byte)i;
|
||||
}
|
||||
Freqs[numItems] = 0;
|
||||
}
|
||||
|
||||
unsigned int Decode(CDecoder *rangeDecoder)
|
||||
{
|
||||
UInt32 threshold = rangeDecoder->GetThreshold(Freqs[0]);
|
||||
unsigned int i;
|
||||
for (i = 1; Freqs[i] > threshold; i++);
|
||||
rangeDecoder->Decode(Freqs[i], Freqs[i - 1], Freqs[0]);
|
||||
unsigned int 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 int 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;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetInStream,
|
||||
public ICompressSetOutStreamSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLZOutWindow _outWindowStream;
|
||||
NRangeCoder::CDecoder _rangeDecoder;
|
||||
|
||||
///////////////////
|
||||
// State
|
||||
UInt64 _outSize;
|
||||
// UInt64 _nowPos64;
|
||||
int _remainLen; // -1 means end of stream. // -2 means need Init
|
||||
UInt32 _rep0;
|
||||
|
||||
int _numDictBits;
|
||||
UInt32 _dictionarySize;
|
||||
|
||||
NRangeCoder::CModelDecoder m_Selector;
|
||||
NRangeCoder::CModelDecoder m_Literals[kNumLitSelectors];
|
||||
NRangeCoder::CModelDecoder m_PosSlot[kNumMatchSelectors];
|
||||
NRangeCoder::CModelDecoder m_LenSlot;
|
||||
|
||||
bool _keepHistory;
|
||||
|
||||
void Init();
|
||||
HRESULT CodeSpec(UInt32 size);
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(
|
||||
ICompressSetInStream,
|
||||
ICompressSetOutStreamSize)
|
||||
|
||||
void ReleaseStreams()
|
||||
{
|
||||
_outWindowStream.ReleaseStream();
|
||||
ReleaseInStream();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
void SetParams(int numDictBits)
|
||||
{
|
||||
_numDictBits = numDictBits;
|
||||
_dictionarySize = (UInt32)1 << numDictBits;
|
||||
}
|
||||
void SetKeepHistory(bool keepHistory)
|
||||
{
|
||||
_keepHistory = keepHistory;
|
||||
}
|
||||
|
||||
CDecoder(): _keepHistory(false) {}
|
||||
virtual ~CDecoder() {}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user