336 lines
7.0 KiB
C++
336 lines
7.0 KiB
C++
// Rar5Decoder.h
|
|
// According to unRAR license, this code may not be used to develop
|
|
// a program that creates RAR archives
|
|
|
|
#ifndef __COMPRESS_RAR5_DECODER_H
|
|
#define __COMPRESS_RAR5_DECODER_H
|
|
|
|
#include "../../../C/Alloc.h"
|
|
#include "../../../C/CpuArch.h"
|
|
|
|
#include "../../Common/MyBuffer.h"
|
|
#include "../../Common/MyCom.h"
|
|
#include "../../Common/MyException.h"
|
|
#include "../../Common/MyVector.h"
|
|
|
|
#include "../ICoder.h"
|
|
|
|
#include "HuffmanDecoder.h"
|
|
|
|
namespace NCompress {
|
|
namespace NRar5 {
|
|
|
|
class CMidBuffer
|
|
{
|
|
Byte *_data;
|
|
size_t _size;
|
|
|
|
CLASS_NO_COPY(CMidBuffer)
|
|
|
|
public:
|
|
CMidBuffer(): _data(NULL), _size(0) {};
|
|
~CMidBuffer() { ::MidFree(_data); }
|
|
|
|
bool IsAllocated() const { return _data != NULL; }
|
|
operator Byte *() { return _data; }
|
|
operator const Byte *() const { return _data; }
|
|
size_t Size() const { return _size; }
|
|
|
|
void AllocAtLeast(size_t size)
|
|
{
|
|
if (size > _size)
|
|
{
|
|
const size_t kMinSize = (1 << 16);
|
|
if (size < kMinSize)
|
|
size = kMinSize;
|
|
::MidFree(_data);
|
|
_data = (Byte *)::MidAlloc(size);
|
|
_size = size;
|
|
}
|
|
}
|
|
};
|
|
|
|
/*
|
|
struct CInBufferException: public CSystemException
|
|
{
|
|
CInBufferException(HRESULT errorCode): CSystemException(errorCode) {}
|
|
};
|
|
*/
|
|
|
|
class CBitDecoder
|
|
{
|
|
public:
|
|
const Byte *_buf;
|
|
unsigned _bitPos;
|
|
bool _wasFinished;
|
|
Byte _blockEndBits7;
|
|
const Byte *_bufCheck2;
|
|
const Byte *_bufCheck;
|
|
Byte *_bufLim;
|
|
Byte *_bufBase;
|
|
|
|
UInt64 _processedSize;
|
|
UInt64 _blockEnd;
|
|
|
|
ISequentialInStream *_stream;
|
|
HRESULT _hres;
|
|
|
|
void SetCheck2()
|
|
{
|
|
_bufCheck2 = _bufCheck;
|
|
if (_bufCheck > _buf)
|
|
{
|
|
UInt64 processed = GetProcessedSize_Round();
|
|
if (_blockEnd < processed)
|
|
_bufCheck2 = _buf;
|
|
else
|
|
{
|
|
UInt64 delta = _blockEnd - processed;
|
|
if ((size_t)(_bufCheck - _buf) > delta)
|
|
_bufCheck2 = _buf + (size_t)delta;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool IsBlockOverRead() const
|
|
{
|
|
UInt64 v = GetProcessedSize_Round();
|
|
if (v < _blockEnd)
|
|
return false;
|
|
if (v > _blockEnd)
|
|
return true;
|
|
return _bitPos > _blockEndBits7;
|
|
}
|
|
|
|
/*
|
|
CBitDecoder() throw():
|
|
_buf(0),
|
|
_bufLim(0),
|
|
_bufBase(0),
|
|
_stream(0),
|
|
_processedSize(0),
|
|
_wasFinished(false)
|
|
{}
|
|
*/
|
|
|
|
void Init() throw()
|
|
{
|
|
_blockEnd = 0;
|
|
_blockEndBits7 = 0;
|
|
|
|
_bitPos = 0;
|
|
_processedSize = 0;
|
|
_buf = _bufBase;
|
|
_bufLim = _bufBase;
|
|
_bufCheck = _buf;
|
|
_bufCheck2 = _buf;
|
|
_wasFinished = false;
|
|
}
|
|
|
|
void Prepare2() throw();
|
|
|
|
void Prepare() throw()
|
|
{
|
|
if (_buf >= _bufCheck)
|
|
Prepare2();
|
|
}
|
|
|
|
bool ExtraBitsWereRead() const
|
|
{
|
|
return _buf >= _bufLim && (_buf > _bufLim || _bitPos != 0);
|
|
}
|
|
|
|
bool InputEofError() const { return ExtraBitsWereRead(); }
|
|
|
|
unsigned GetProcessedBits7() const { return _bitPos; }
|
|
UInt64 GetProcessedSize_Round() const { return _processedSize + (_buf - _bufBase); }
|
|
UInt64 GetProcessedSize() const { return _processedSize + (_buf - _bufBase) + ((_bitPos + 7) >> 3); }
|
|
|
|
void AlignToByte()
|
|
{
|
|
_buf += (_bitPos + 7) >> 3;
|
|
_bitPos = 0;
|
|
}
|
|
|
|
Byte ReadByteInAligned()
|
|
{
|
|
return *_buf++;
|
|
}
|
|
|
|
UInt32 GetValue(unsigned numBits)
|
|
{
|
|
UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2];
|
|
v >>= (24 - numBits - _bitPos);
|
|
return v & ((1 << numBits) - 1);
|
|
}
|
|
|
|
void MovePos(unsigned numBits)
|
|
{
|
|
_bitPos += numBits;
|
|
_buf += (_bitPos >> 3);
|
|
_bitPos &= 7;
|
|
}
|
|
|
|
UInt32 ReadBits9(unsigned numBits)
|
|
{
|
|
const Byte *buf = _buf;
|
|
UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1];
|
|
v &= ((UInt32)0xFFFF >> _bitPos);
|
|
numBits += _bitPos;
|
|
v >>= (16 - numBits);
|
|
_buf = buf + (numBits >> 3);
|
|
_bitPos = numBits & 7;
|
|
return v;
|
|
}
|
|
|
|
UInt32 ReadBits9fix(unsigned numBits)
|
|
{
|
|
const Byte *buf = _buf;
|
|
UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1];
|
|
UInt32 mask = ((1 << numBits) - 1);
|
|
numBits += _bitPos;
|
|
v >>= (16 - numBits);
|
|
_buf = buf + (numBits >> 3);
|
|
_bitPos = numBits & 7;
|
|
return v & mask;
|
|
}
|
|
|
|
UInt32 ReadBits32(unsigned numBits)
|
|
{
|
|
UInt32 mask = ((1 << numBits) - 1);
|
|
numBits += _bitPos;
|
|
const Byte *buf = _buf;
|
|
UInt32 v = GetBe32(buf);
|
|
if (numBits > 32)
|
|
{
|
|
v <<= (numBits - 32);
|
|
v |= (UInt32)buf[4] >> (40 - numBits);
|
|
}
|
|
else
|
|
v >>= (32 - numBits);
|
|
_buf = buf + (numBits >> 3);
|
|
_bitPos = numBits & 7;
|
|
return v & mask;
|
|
}
|
|
};
|
|
|
|
|
|
struct CFilter
|
|
{
|
|
Byte Type;
|
|
Byte Channels;
|
|
UInt32 Size;
|
|
UInt64 Start;
|
|
};
|
|
|
|
|
|
const unsigned kNumReps = 4;
|
|
const unsigned kLenTableSize = 11 * 4;
|
|
const unsigned kMainTableSize = 256 + 1 + 1 + kNumReps + kLenTableSize;
|
|
const unsigned kDistTableSize = 64;
|
|
const unsigned kNumAlignBits = 4;
|
|
const unsigned kAlignTableSize = (1 << kNumAlignBits);
|
|
const unsigned kLevelTableSize = 20;
|
|
const unsigned kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize;
|
|
|
|
const unsigned kNumHuffmanBits = 15;
|
|
|
|
class CDecoder:
|
|
public ICompressCoder,
|
|
public ICompressSetDecoderProperties2,
|
|
public CMyUnknownImp
|
|
{
|
|
bool _useAlignBits;
|
|
bool _isLastBlock;
|
|
bool _unpackSize_Defined;
|
|
// bool _packSize_Defined;
|
|
|
|
bool _unsupportedFilter;
|
|
bool _lzError;
|
|
bool _writeError;
|
|
|
|
// CBitDecoder _bitStream;
|
|
Byte *_window;
|
|
size_t _winPos;
|
|
size_t _winSize;
|
|
size_t _winMask;
|
|
|
|
UInt64 _lzSize;
|
|
|
|
unsigned _numCorrectDistSymbols;
|
|
unsigned _numUnusedFilters;
|
|
|
|
UInt64 _lzWritten;
|
|
UInt64 _lzFileStart;
|
|
UInt64 _unpackSize;
|
|
// UInt64 _packSize;
|
|
UInt64 _lzEnd;
|
|
UInt64 _writtenFileSize;
|
|
size_t _winSizeAllocated;
|
|
|
|
Byte _dictSizeLog;
|
|
bool _tableWasFilled;
|
|
bool _isSolid;
|
|
bool _wasInit;
|
|
|
|
UInt32 _reps[kNumReps];
|
|
UInt32 _lastLen;
|
|
|
|
UInt64 _filterEnd;
|
|
CMidBuffer _filterSrc;
|
|
CMidBuffer _filterDst;
|
|
|
|
CRecordVector<CFilter> _filters;
|
|
|
|
ISequentialInStream *_inStream;
|
|
ISequentialOutStream *_outStream;
|
|
ICompressProgressInfo *_progress;
|
|
Byte *_inputBuf;
|
|
|
|
NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
|
|
NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
|
|
NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
|
|
NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
|
|
NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
|
|
|
|
|
|
void InitFilters()
|
|
{
|
|
_numUnusedFilters = 0;
|
|
_filters.Clear();
|
|
}
|
|
|
|
void DeleteUnusedFilters()
|
|
{
|
|
if (_numUnusedFilters != 0)
|
|
{
|
|
_filters.DeleteFrontal(_numUnusedFilters);
|
|
_numUnusedFilters = 0;
|
|
}
|
|
}
|
|
|
|
HRESULT WriteData(const Byte *data, size_t size);
|
|
HRESULT ExecuteFilter(const CFilter &f);
|
|
HRESULT WriteBuf();
|
|
HRESULT AddFilter(CBitDecoder &_bitStream);
|
|
|
|
HRESULT ReadTables(CBitDecoder &_bitStream);
|
|
HRESULT DecodeLZ();
|
|
HRESULT CodeReal();
|
|
|
|
public:
|
|
CDecoder();
|
|
~CDecoder();
|
|
|
|
MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
|
|
|
|
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
|
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
|
|
|
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
|
};
|
|
|
|
}}
|
|
|
|
#endif
|