mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 15:14:59 -06:00
265 lines
6.2 KiB
C++
Executable File
265 lines
6.2 KiB
C++
Executable File
// QuantumDecoder.h
|
|
|
|
#ifndef __COMPRESS_QUANTUM_DECODER_H
|
|
#define __COMPRESS_QUANTUM_DECODER_H
|
|
|
|
#include "../../Common/MyCom.h"
|
|
|
|
#include "../ICoder.h"
|
|
|
|
#include "../Common/InBuffer.h"
|
|
|
|
#include "LzOutWindow.h"
|
|
|
|
namespace NCompress {
|
|
namespace NQuantum {
|
|
|
|
class CStreamBitDecoder
|
|
{
|
|
UInt32 Value;
|
|
CInBuffer Stream;
|
|
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()
|
|
{
|
|
Stream.Init();
|
|
Value = 0x10000;
|
|
}
|
|
|
|
UInt64 GetProcessedSize() const { return Stream.GetProcessedSize(); }
|
|
bool WasFinished() const { return Stream.WasFinished(); }
|
|
|
|
UInt32 ReadBit()
|
|
{
|
|
if (Value >= 0x10000)
|
|
Value = 0x100 | Stream.ReadByte();
|
|
UInt32 res = (Value >> 7) & 1;
|
|
Value <<= 1;
|
|
return res;
|
|
}
|
|
|
|
UInt32 ReadBits(int numBits) // numBits > 0
|
|
{
|
|
UInt32 res = 0;
|
|
do
|
|
res = (res << 1) | ReadBit();
|
|
while (--numBits != 0);
|
|
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
|
|
{
|
|
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 NumItems;
|
|
unsigned ReorderCount;
|
|
UInt16 Freqs[kNumSymbolsMax + 1];
|
|
Byte Values[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;
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
class CDecoder:
|
|
public ICompressCoder,
|
|
public ICompressSetInStream,
|
|
public ICompressSetOutStreamSize,
|
|
public CMyUnknownImp
|
|
{
|
|
CLzOutWindow _outWindowStream;
|
|
NRangeCoder::CDecoder _rangeDecoder;
|
|
|
|
UInt64 _outSize;
|
|
int _remainLen; // -1 means end of stream. // -2 means need Init
|
|
UInt32 _rep0;
|
|
|
|
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);
|
|
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; }
|
|
void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
|
|
CDecoder(): _keepHistory(false) {}
|
|
virtual ~CDecoder() {}
|
|
};
|
|
|
|
}}
|
|
|
|
#endif
|