chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: LGPL-2.1-or-later
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
// Compress/BZip2Const.h
|
||||
|
||||
#ifndef __COMPRESS_BZIP2_CONST_H
|
||||
#define __COMPRESS_BZIP2_CONST_H
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBZip2 {
|
||||
|
||||
const Byte kArSig0 = 'B';
|
||||
const Byte kArSig1 = 'Z';
|
||||
const Byte kArSig2 = 'h';
|
||||
const Byte kArSig3 = '0';
|
||||
|
||||
const Byte kFinSig0 = 0x17;
|
||||
const Byte kFinSig1 = 0x72;
|
||||
const Byte kFinSig2 = 0x45;
|
||||
const Byte kFinSig3 = 0x38;
|
||||
const Byte kFinSig4 = 0x50;
|
||||
const Byte kFinSig5 = 0x90;
|
||||
|
||||
const Byte kBlockSig0 = 0x31;
|
||||
const Byte kBlockSig1 = 0x41;
|
||||
const Byte kBlockSig2 = 0x59;
|
||||
const Byte kBlockSig3 = 0x26;
|
||||
const Byte kBlockSig4 = 0x53;
|
||||
const Byte kBlockSig5 = 0x59;
|
||||
|
||||
const unsigned kNumOrigBits = 24;
|
||||
|
||||
const unsigned kNumTablesBits = 3;
|
||||
const unsigned kNumTablesMin = 2;
|
||||
const unsigned kNumTablesMax = 6;
|
||||
|
||||
const unsigned kNumLevelsBits = 5;
|
||||
|
||||
const unsigned kMaxHuffmanLen = 20; // Check it
|
||||
|
||||
const unsigned kMaxAlphaSize = 258;
|
||||
|
||||
const unsigned kGroupSize = 50;
|
||||
|
||||
const unsigned kBlockSizeMultMin = 1;
|
||||
const unsigned kBlockSizeMultMax = 9;
|
||||
|
||||
const UInt32 kBlockSizeStep = 100000;
|
||||
const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep;
|
||||
|
||||
const unsigned kNumSelectorsBits = 15;
|
||||
const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize));
|
||||
|
||||
const unsigned kRleModeRepSize = 4;
|
||||
|
||||
/*
|
||||
The number of selectors stored in bzip2 block:
|
||||
(numSelectors <= 18001) - must work with any decoder.
|
||||
(numSelectors == 18002) - works with bzip2 1.0.6 decoder and all derived decoders.
|
||||
(numSelectors > 18002)
|
||||
7-Zip decoder doesn't support it.
|
||||
bzip2 1.0.6 decoder can overflow selector[18002] arrays. But there are another
|
||||
arrays after selector arrays. So the compiled code works.
|
||||
lbzip2 2.5 encoder can write up to (18001 + 7) selectors.
|
||||
*/
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
// BZip2Crc.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "BZip2Crc.h"
|
||||
|
||||
UInt32 CBZip2Crc::Table[256];
|
||||
|
||||
static const UInt32 kBZip2CrcPoly = 0x04c11db7; /* AUTODIN II, Ethernet, & FDDI */
|
||||
|
||||
void CBZip2Crc::InitTable()
|
||||
{
|
||||
for (UInt32 i = 0; i < 256; i++)
|
||||
{
|
||||
UInt32 r = (i << 24);
|
||||
for (unsigned j = 0; j < 8; j++)
|
||||
r = (r << 1) ^ (kBZip2CrcPoly & ((UInt32)0 - (r >> 31)));
|
||||
Table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
class CBZip2CrcTableInit
|
||||
{
|
||||
public:
|
||||
CBZip2CrcTableInit() { CBZip2Crc::InitTable(); }
|
||||
} g_BZip2CrcTableInit;
|
||||
@@ -0,0 +1,31 @@
|
||||
// BZip2Crc.h
|
||||
|
||||
#ifndef __BZIP2_CRC_H
|
||||
#define __BZIP2_CRC_H
|
||||
|
||||
#include "../../Common/MyTypes.h"
|
||||
|
||||
class CBZip2Crc
|
||||
{
|
||||
UInt32 _value;
|
||||
static UInt32 Table[256];
|
||||
public:
|
||||
static void InitTable();
|
||||
CBZip2Crc(): _value(0xFFFFFFFF) {};
|
||||
void Init() { _value = 0xFFFFFFFF; }
|
||||
void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); }
|
||||
void UpdateByte(unsigned int b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); }
|
||||
UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; }
|
||||
};
|
||||
|
||||
class CBZip2CombinedCrc
|
||||
{
|
||||
UInt32 _value;
|
||||
public:
|
||||
CBZip2CombinedCrc(): _value(0){};
|
||||
void Init() { _value = 0; }
|
||||
void Update(UInt32 v) { _value = ((_value << 1) | (_value >> 31)) ^ v; }
|
||||
UInt32 GetDigest() const { return _value ; }
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,382 @@
|
||||
// Compress/BZip2Decoder.h
|
||||
|
||||
#ifndef __COMPRESS_BZIP2_DECODER_H
|
||||
#define __COMPRESS_BZIP2_DECODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
// #define NO_READ_FROM_CODER
|
||||
// #define _7ZIP_ST
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
#include "../../Windows/Synchronization.h"
|
||||
#include "../../Windows/Thread.h"
|
||||
#endif
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "BZip2Const.h"
|
||||
#include "BZip2Crc.h"
|
||||
#include "HuffmanDecoder.h"
|
||||
#include "Mtf8.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBZip2 {
|
||||
|
||||
bool IsEndSig(const Byte *p) throw();
|
||||
bool IsBlockSig(const Byte *p) throw();
|
||||
|
||||
const unsigned kNumTableBits = 9;
|
||||
const unsigned kNumBitsMax = kMaxHuffmanLen;
|
||||
|
||||
typedef NHuffman::CDecoder<kMaxHuffmanLen, kMaxAlphaSize, kNumTableBits> CHuffmanDecoder;
|
||||
|
||||
|
||||
struct CBlockProps
|
||||
{
|
||||
UInt32 blockSize;
|
||||
UInt32 origPtr;
|
||||
unsigned randMode;
|
||||
|
||||
CBlockProps(): blockSize(0), origPtr(0), randMode(0) {}
|
||||
};
|
||||
|
||||
|
||||
struct CBitDecoder
|
||||
{
|
||||
unsigned _numBits;
|
||||
UInt32 _value;
|
||||
const Byte *_buf;
|
||||
const Byte *_lim;
|
||||
|
||||
void InitBitDecoder()
|
||||
{
|
||||
_numBits = 0;
|
||||
_value = 0;
|
||||
}
|
||||
|
||||
void AlignToByte()
|
||||
{
|
||||
unsigned bits = _numBits & 7;
|
||||
_numBits -= bits;
|
||||
_value <<= bits;
|
||||
}
|
||||
|
||||
/*
|
||||
bool AreRemainByteBitsEmpty() const
|
||||
{
|
||||
unsigned bits = _numBits & 7;
|
||||
if (bits != 0)
|
||||
return (_value >> (32 - bits)) == 0;
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
SRes ReadByte(int &b);
|
||||
};
|
||||
|
||||
|
||||
struct CBase: public CBitDecoder
|
||||
{
|
||||
unsigned numInUse;
|
||||
UInt32 groupIndex;
|
||||
UInt32 groupSize;
|
||||
unsigned runPower;
|
||||
UInt32 runCounter;
|
||||
UInt32 blockSize;
|
||||
|
||||
UInt32 *Counters;
|
||||
UInt32 blockSizeMax;
|
||||
|
||||
unsigned state;
|
||||
unsigned state2;
|
||||
unsigned state3;
|
||||
unsigned state4;
|
||||
unsigned state5;
|
||||
unsigned numTables;
|
||||
UInt32 numSelectors;
|
||||
|
||||
CBlockProps Props;
|
||||
|
||||
private:
|
||||
CMtf8Decoder mtf;
|
||||
Byte selectors[kNumSelectorsMax];
|
||||
CHuffmanDecoder huffs[kNumTablesMax];
|
||||
|
||||
Byte lens[kMaxAlphaSize];
|
||||
|
||||
Byte temp[10];
|
||||
|
||||
public:
|
||||
UInt32 crc;
|
||||
CBZip2CombinedCrc CombinedCrc;
|
||||
|
||||
bool IsBz;
|
||||
bool StreamCrcError;
|
||||
bool MinorError;
|
||||
bool NeedMoreInput;
|
||||
|
||||
bool DecodeAllStreams;
|
||||
|
||||
UInt64 NumStreams;
|
||||
UInt64 NumBlocks;
|
||||
UInt64 FinishedPackSize;
|
||||
|
||||
ISequentialInStream *InStream;
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
CMyComPtr<ISequentialInStream> InStreamRef;
|
||||
#endif
|
||||
|
||||
CBase():
|
||||
StreamCrcError(false),
|
||||
MinorError(false),
|
||||
NeedMoreInput(false),
|
||||
|
||||
DecodeAllStreams(false),
|
||||
|
||||
NumStreams(0),
|
||||
NumBlocks(0),
|
||||
FinishedPackSize(0)
|
||||
{}
|
||||
|
||||
void InitNumStreams2()
|
||||
{
|
||||
StreamCrcError = false;
|
||||
MinorError = false;
|
||||
NeedMoreInput = 0;
|
||||
NumStreams = 0;
|
||||
NumBlocks = 0;
|
||||
FinishedPackSize = 0;
|
||||
}
|
||||
|
||||
SRes ReadStreamSignature2();
|
||||
SRes ReadBlockSignature2();
|
||||
|
||||
/* ReadBlock2() : Props->randMode:
|
||||
in: need read randMode bit
|
||||
out: randMode status */
|
||||
SRes ReadBlock2();
|
||||
};
|
||||
|
||||
|
||||
class CSpecState
|
||||
{
|
||||
UInt32 _tPos;
|
||||
unsigned _prevByte;
|
||||
int _reps;
|
||||
|
||||
public:
|
||||
CBZip2Crc _crc;
|
||||
UInt32 _blockSize;
|
||||
UInt32 *_tt;
|
||||
|
||||
int _randToGo;
|
||||
unsigned _randIndex;
|
||||
|
||||
void Init(UInt32 origPtr, unsigned randMode) throw();
|
||||
|
||||
bool Finished() const { return _reps <= 0 && _blockSize == 0; }
|
||||
|
||||
Byte *Decode(Byte *data, size_t size) throw();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class CDecoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
public ICompressSetInStream,
|
||||
public ICompressSetOutStreamSize,
|
||||
public ISequentialInStream,
|
||||
#endif
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
public ICompressSetCoderMt,
|
||||
#endif
|
||||
|
||||
public CMyUnknownImp
|
||||
{
|
||||
Byte *_outBuf;
|
||||
size_t _outPos;
|
||||
UInt64 _outWritten;
|
||||
ISequentialOutStream *_outStream;
|
||||
HRESULT _writeRes;
|
||||
|
||||
protected:
|
||||
HRESULT ErrorResult; // for ISequentialInStream::Read mode only
|
||||
|
||||
public:
|
||||
|
||||
UInt32 _calcedBlockCrc;
|
||||
bool _blockFinished;
|
||||
bool BlockCrcError;
|
||||
|
||||
bool FinishMode;
|
||||
bool _outSizeDefined;
|
||||
UInt64 _outSize;
|
||||
UInt64 _outPosTotal;
|
||||
|
||||
CSpecState _spec;
|
||||
UInt32 *_counters;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
|
||||
struct CBlock
|
||||
{
|
||||
bool StopScout;
|
||||
|
||||
bool WasFinished;
|
||||
bool Crc_Defined;
|
||||
// bool NextCrc_Defined;
|
||||
|
||||
UInt32 Crc;
|
||||
UInt32 NextCrc;
|
||||
HRESULT Res;
|
||||
UInt64 PackPos;
|
||||
|
||||
CBlockProps Props;
|
||||
};
|
||||
|
||||
CBlock _block;
|
||||
|
||||
bool NeedWaitScout;
|
||||
bool MtMode;
|
||||
|
||||
NWindows::CThread Thread;
|
||||
NWindows::NSynchronization::CAutoResetEvent DecoderEvent;
|
||||
NWindows::NSynchronization::CAutoResetEvent ScoutEvent;
|
||||
// HRESULT ScoutRes;
|
||||
|
||||
Byte MtPad[1 << 7]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
|
||||
|
||||
|
||||
void RunScout();
|
||||
|
||||
void WaitScout()
|
||||
{
|
||||
if (NeedWaitScout)
|
||||
{
|
||||
DecoderEvent.Lock();
|
||||
NeedWaitScout = false;
|
||||
}
|
||||
}
|
||||
|
||||
class CWaitScout_Releaser
|
||||
{
|
||||
CDecoder *_decoder;
|
||||
public:
|
||||
CWaitScout_Releaser(CDecoder *decoder): _decoder(decoder) {}
|
||||
~CWaitScout_Releaser() { _decoder->WaitScout(); }
|
||||
};
|
||||
|
||||
HRESULT CreateThread();
|
||||
|
||||
#endif
|
||||
|
||||
Byte *_inBuf;
|
||||
UInt64 _inProcessed;
|
||||
bool _inputFinished;
|
||||
HRESULT _inputRes;
|
||||
|
||||
CBase Base;
|
||||
|
||||
bool GetCrcError() const { return BlockCrcError || Base.StreamCrcError; }
|
||||
|
||||
void InitOutSize(const UInt64 *outSize);
|
||||
|
||||
bool CreateInputBufer();
|
||||
|
||||
void InitInputBuffer()
|
||||
{
|
||||
_inProcessed = 0;
|
||||
Base._buf = _inBuf;
|
||||
Base._lim = _inBuf;
|
||||
Base.InitBitDecoder();
|
||||
}
|
||||
|
||||
UInt64 GetInputProcessedSize() const
|
||||
{
|
||||
// for NSIS case : we need also look the number of bits in bitDecoder
|
||||
return _inProcessed + (Base._buf - _inBuf);
|
||||
}
|
||||
|
||||
UInt64 GetOutProcessedSize() const { return _outWritten + _outPos; }
|
||||
|
||||
HRESULT ReadInput();
|
||||
|
||||
void StartNewStream();
|
||||
|
||||
HRESULT ReadStreamSignature();
|
||||
HRESULT StartRead();
|
||||
|
||||
HRESULT ReadBlockSignature();
|
||||
HRESULT ReadBlock();
|
||||
|
||||
HRESULT Flush();
|
||||
HRESULT DecodeBlock(const CBlockProps &props);
|
||||
HRESULT DecodeStreams(ICompressProgressInfo *progress);
|
||||
|
||||
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
|
||||
MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
|
||||
#endif
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
|
||||
#endif
|
||||
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
|
||||
UInt64 GetNumStreams() const { return Base.NumStreams; }
|
||||
UInt64 GetNumBlocks() const { return Base.NumBlocks; }
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
|
||||
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
|
||||
STDMETHOD(ReleaseInStream)();
|
||||
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
|
||||
#endif
|
||||
|
||||
CDecoder();
|
||||
~CDecoder();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
|
||||
class CNsisDecoder : public CDecoder
|
||||
{
|
||||
public:
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,893 @@
|
||||
// BZip2Encoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
#include "../../../C/BwtSort.h"
|
||||
#include "../../../C/HuffEnc.h"
|
||||
|
||||
#include "BZip2Crc.h"
|
||||
#include "BZip2Encoder.h"
|
||||
#include "Mtf8.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBZip2 {
|
||||
|
||||
const unsigned kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20
|
||||
|
||||
static const UInt32 kBufferSize = (1 << 17);
|
||||
static const unsigned kNumHuffPasses = 4;
|
||||
|
||||
bool CThreadInfo::Alloc()
|
||||
{
|
||||
if (m_BlockSorterIndex == 0)
|
||||
{
|
||||
m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32));
|
||||
if (m_BlockSorterIndex == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_Block == 0)
|
||||
{
|
||||
m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10));
|
||||
if (m_Block == 0)
|
||||
return false;
|
||||
m_MtfArray = m_Block + kBlockSizeMax;
|
||||
m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CThreadInfo::Free()
|
||||
{
|
||||
::BigFree(m_BlockSorterIndex);
|
||||
m_BlockSorterIndex = 0;
|
||||
::MidFree(m_Block);
|
||||
m_Block = 0;
|
||||
}
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
|
||||
static THREAD_FUNC_DECL MFThread(void *threadCoderInfo)
|
||||
{
|
||||
return ((CThreadInfo *)threadCoderInfo)->ThreadFunc();
|
||||
}
|
||||
|
||||
#define RINOK_THREAD(x) { WRes __result_ = (x); if (__result_ != 0) return __result_; }
|
||||
|
||||
HRESULT CThreadInfo::Create()
|
||||
{
|
||||
RINOK_THREAD(StreamWasFinishedEvent.Create());
|
||||
RINOK_THREAD(WaitingWasStartedEvent.Create());
|
||||
RINOK_THREAD(CanWriteEvent.Create());
|
||||
RINOK_THREAD(Thread.Create(MFThread, this));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CThreadInfo::FinishStream(bool needLeave)
|
||||
{
|
||||
Encoder->StreamWasFinished = true;
|
||||
StreamWasFinishedEvent.Set();
|
||||
if (needLeave)
|
||||
Encoder->CS.Leave();
|
||||
Encoder->CanStartWaitingEvent.Lock();
|
||||
WaitingWasStartedEvent.Set();
|
||||
}
|
||||
|
||||
DWORD CThreadInfo::ThreadFunc()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
Encoder->CanProcessEvent.Lock();
|
||||
Encoder->CS.Enter();
|
||||
if (Encoder->CloseThreads)
|
||||
{
|
||||
Encoder->CS.Leave();
|
||||
return 0;
|
||||
}
|
||||
if (Encoder->StreamWasFinished)
|
||||
{
|
||||
FinishStream(true);
|
||||
continue;
|
||||
}
|
||||
HRESULT res = S_OK;
|
||||
bool needLeave = true;
|
||||
try
|
||||
{
|
||||
UInt32 blockSize = Encoder->ReadRleBlock(m_Block);
|
||||
m_PackSize = Encoder->m_InStream.GetProcessedSize();
|
||||
m_BlockIndex = Encoder->NextBlockIndex;
|
||||
if (++Encoder->NextBlockIndex == Encoder->NumThreads)
|
||||
Encoder->NextBlockIndex = 0;
|
||||
if (blockSize == 0)
|
||||
{
|
||||
FinishStream(true);
|
||||
continue;
|
||||
}
|
||||
Encoder->CS.Leave();
|
||||
needLeave = false;
|
||||
res = EncodeBlock3(blockSize);
|
||||
}
|
||||
catch(const CInBufferException &e) { res = e.ErrorCode; }
|
||||
catch(const COutBufferException &e) { res = e.ErrorCode; }
|
||||
catch(...) { res = E_FAIL; }
|
||||
if (res != S_OK)
|
||||
{
|
||||
Encoder->Result = res;
|
||||
FinishStream(needLeave);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void CEncProps::Normalize(int level)
|
||||
{
|
||||
if (level < 0) level = 5;
|
||||
if (level > 9) level = 9;
|
||||
|
||||
if (NumPasses == (UInt32)(Int32)-1)
|
||||
NumPasses = (level >= 9 ? 7 : (level >= 7 ? 2 : 1));
|
||||
if (NumPasses < 1) NumPasses = 1;
|
||||
if (NumPasses > kNumPassesMax) NumPasses = kNumPassesMax;
|
||||
|
||||
if (BlockSizeMult == (UInt32)(Int32)-1)
|
||||
BlockSizeMult = (level >= 5 ? 9 : (level >= 1 ? level * 2 - 1: 1));
|
||||
if (BlockSizeMult < kBlockSizeMultMin) BlockSizeMult = kBlockSizeMultMin;
|
||||
if (BlockSizeMult > kBlockSizeMultMax) BlockSizeMult = kBlockSizeMultMax;
|
||||
}
|
||||
|
||||
CEncoder::CEncoder()
|
||||
{
|
||||
_props.Normalize(-1);
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
ThreadsInfo = 0;
|
||||
m_NumThreadsPrev = 0;
|
||||
NumThreads = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
CEncoder::~CEncoder()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
HRESULT CEncoder::Create()
|
||||
{
|
||||
RINOK_THREAD(CanProcessEvent.CreateIfNotCreated());
|
||||
RINOK_THREAD(CanStartWaitingEvent.CreateIfNotCreated());
|
||||
if (ThreadsInfo != 0 && m_NumThreadsPrev == NumThreads)
|
||||
return S_OK;
|
||||
try
|
||||
{
|
||||
Free();
|
||||
MtMode = (NumThreads > 1);
|
||||
m_NumThreadsPrev = NumThreads;
|
||||
ThreadsInfo = new CThreadInfo[NumThreads];
|
||||
if (ThreadsInfo == 0)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
catch(...) { return E_OUTOFMEMORY; }
|
||||
for (UInt32 t = 0; t < NumThreads; t++)
|
||||
{
|
||||
CThreadInfo &ti = ThreadsInfo[t];
|
||||
ti.Encoder = this;
|
||||
if (MtMode)
|
||||
{
|
||||
HRESULT res = ti.Create();
|
||||
if (res != S_OK)
|
||||
{
|
||||
NumThreads = t;
|
||||
Free();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CEncoder::Free()
|
||||
{
|
||||
if (!ThreadsInfo)
|
||||
return;
|
||||
CloseThreads = true;
|
||||
CanProcessEvent.Set();
|
||||
for (UInt32 t = 0; t < NumThreads; t++)
|
||||
{
|
||||
CThreadInfo &ti = ThreadsInfo[t];
|
||||
if (MtMode)
|
||||
ti.Thread.Wait();
|
||||
ti.Free();
|
||||
}
|
||||
delete []ThreadsInfo;
|
||||
ThreadsInfo = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
UInt32 CEncoder::ReadRleBlock(Byte *buffer)
|
||||
{
|
||||
UInt32 i = 0;
|
||||
Byte prevByte;
|
||||
if (m_InStream.ReadByte(prevByte))
|
||||
{
|
||||
UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1;
|
||||
unsigned numReps = 1;
|
||||
buffer[i++] = prevByte;
|
||||
while (i < blockSize) // "- 1" to support RLE
|
||||
{
|
||||
Byte b;
|
||||
if (!m_InStream.ReadByte(b))
|
||||
break;
|
||||
if (b != prevByte)
|
||||
{
|
||||
if (numReps >= kRleModeRepSize)
|
||||
buffer[i++] = (Byte)(numReps - kRleModeRepSize);
|
||||
buffer[i++] = b;
|
||||
numReps = 1;
|
||||
prevByte = b;
|
||||
continue;
|
||||
}
|
||||
numReps++;
|
||||
if (numReps <= kRleModeRepSize)
|
||||
buffer[i++] = b;
|
||||
else if (numReps == kRleModeRepSize + 255)
|
||||
{
|
||||
buffer[i++] = (Byte)(numReps - kRleModeRepSize);
|
||||
numReps = 0;
|
||||
}
|
||||
}
|
||||
// it's to support original BZip2 decoder
|
||||
if (numReps >= kRleModeRepSize)
|
||||
buffer[i++] = (Byte)(numReps - kRleModeRepSize);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); }
|
||||
void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); }
|
||||
void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); }
|
||||
void CThreadInfo::WriteCrc2(UInt32 v)
|
||||
{
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
WriteByte2(((Byte)(v >> (24 - i * 8))));
|
||||
}
|
||||
|
||||
void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); }
|
||||
void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); }
|
||||
// void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); }
|
||||
void CEncoder::WriteCrc(UInt32 v)
|
||||
{
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
WriteByte(((Byte)(v >> (24 - i * 8))));
|
||||
}
|
||||
|
||||
|
||||
// blockSize > 0
|
||||
void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
|
||||
{
|
||||
WriteBit2(0); // Randomised = false
|
||||
|
||||
{
|
||||
UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
|
||||
// if (m_BlockSorterIndex[origPtr] != 0) throw 1;
|
||||
m_BlockSorterIndex[origPtr] = blockSize;
|
||||
WriteBits2(origPtr, kNumOrigBits);
|
||||
}
|
||||
|
||||
CMtf8Encoder mtf;
|
||||
unsigned numInUse = 0;
|
||||
{
|
||||
Byte inUse[256];
|
||||
Byte inUse16[16];
|
||||
UInt32 i;
|
||||
for (i = 0; i < 256; i++)
|
||||
inUse[i] = 0;
|
||||
for (i = 0; i < 16; i++)
|
||||
inUse16[i] = 0;
|
||||
for (i = 0; i < blockSize; i++)
|
||||
inUse[block[i]] = 1;
|
||||
for (i = 0; i < 256; i++)
|
||||
if (inUse[i])
|
||||
{
|
||||
inUse16[i >> 4] = 1;
|
||||
mtf.Buf[numInUse++] = (Byte)i;
|
||||
}
|
||||
for (i = 0; i < 16; i++)
|
||||
WriteBit2(inUse16[i]);
|
||||
for (i = 0; i < 256; i++)
|
||||
if (inUse16[i >> 4])
|
||||
WriteBit2(inUse[i]);
|
||||
}
|
||||
unsigned alphaSize = numInUse + 2;
|
||||
|
||||
Byte *mtfs = m_MtfArray;
|
||||
UInt32 mtfArraySize = 0;
|
||||
UInt32 symbolCounts[kMaxAlphaSize];
|
||||
{
|
||||
for (unsigned i = 0; i < kMaxAlphaSize; i++)
|
||||
symbolCounts[i] = 0;
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 rleSize = 0;
|
||||
UInt32 i = 0;
|
||||
const UInt32 *bsIndex = m_BlockSorterIndex;
|
||||
block--;
|
||||
do
|
||||
{
|
||||
unsigned pos = mtf.FindAndMove(block[bsIndex[i]]);
|
||||
if (pos == 0)
|
||||
rleSize++;
|
||||
else
|
||||
{
|
||||
while (rleSize != 0)
|
||||
{
|
||||
rleSize--;
|
||||
mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
|
||||
symbolCounts[rleSize & 1]++;
|
||||
rleSize >>= 1;
|
||||
}
|
||||
if (pos >= 0xFE)
|
||||
{
|
||||
mtfs[mtfArraySize++] = 0xFF;
|
||||
mtfs[mtfArraySize++] = (Byte)(pos - 0xFE);
|
||||
}
|
||||
else
|
||||
mtfs[mtfArraySize++] = (Byte)(pos + 1);
|
||||
symbolCounts[(size_t)pos + 1]++;
|
||||
}
|
||||
}
|
||||
while (++i < blockSize);
|
||||
|
||||
while (rleSize != 0)
|
||||
{
|
||||
rleSize--;
|
||||
mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
|
||||
symbolCounts[rleSize & 1]++;
|
||||
rleSize >>= 1;
|
||||
}
|
||||
|
||||
if (alphaSize < 256)
|
||||
mtfs[mtfArraySize++] = (Byte)(alphaSize - 1);
|
||||
else
|
||||
{
|
||||
mtfs[mtfArraySize++] = 0xFF;
|
||||
mtfs[mtfArraySize++] = (Byte)(alphaSize - 256);
|
||||
}
|
||||
symbolCounts[(size_t)alphaSize - 1]++;
|
||||
}
|
||||
|
||||
UInt32 numSymbols = 0;
|
||||
{
|
||||
for (unsigned i = 0; i < kMaxAlphaSize; i++)
|
||||
numSymbols += symbolCounts[i];
|
||||
}
|
||||
|
||||
unsigned bestNumTables = kNumTablesMin;
|
||||
UInt32 bestPrice = 0xFFFFFFFF;
|
||||
UInt32 startPos = m_OutStreamCurrent->GetPos();
|
||||
Byte startCurByte = m_OutStreamCurrent->GetCurByte();
|
||||
for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
|
||||
{
|
||||
unsigned numTables;
|
||||
|
||||
if (m_OptimizeNumTables)
|
||||
{
|
||||
m_OutStreamCurrent->SetPos(startPos);
|
||||
m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
|
||||
if (nt <= kNumTablesMax)
|
||||
numTables = nt;
|
||||
else
|
||||
numTables = bestNumTables;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numSymbols < 200) numTables = 2;
|
||||
else if (numSymbols < 600) numTables = 3;
|
||||
else if (numSymbols < 1200) numTables = 4;
|
||||
else if (numSymbols < 2400) numTables = 5;
|
||||
else numTables = 6;
|
||||
}
|
||||
|
||||
WriteBits2(numTables, kNumTablesBits);
|
||||
|
||||
UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
|
||||
WriteBits2(numSelectors, kNumSelectorsBits);
|
||||
|
||||
{
|
||||
UInt32 remFreq = numSymbols;
|
||||
unsigned gs = 0;
|
||||
unsigned t = numTables;
|
||||
do
|
||||
{
|
||||
UInt32 tFreq = remFreq / t;
|
||||
unsigned ge = gs;
|
||||
UInt32 aFreq = 0;
|
||||
while (aFreq < tFreq) // && ge < alphaSize)
|
||||
aFreq += symbolCounts[ge++];
|
||||
|
||||
if (ge > gs + 1 && t != numTables && t != 1 && (((numTables - t) & 1) == 1))
|
||||
aFreq -= symbolCounts[--ge];
|
||||
|
||||
Byte *lens = Lens[(size_t)t - 1];
|
||||
unsigned i = 0;
|
||||
do
|
||||
lens[i] = (Byte)((i >= gs && i < ge) ? 0 : 1);
|
||||
while (++i < alphaSize);
|
||||
gs = ge;
|
||||
remFreq -= aFreq;
|
||||
}
|
||||
while (--t != 0);
|
||||
}
|
||||
|
||||
|
||||
for (unsigned pass = 0; pass < kNumHuffPasses; pass++)
|
||||
{
|
||||
{
|
||||
unsigned t = 0;
|
||||
do
|
||||
memset(Freqs[t], 0, sizeof(Freqs[t]));
|
||||
while (++t < numTables);
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 mtfPos = 0;
|
||||
UInt32 g = 0;
|
||||
do
|
||||
{
|
||||
UInt32 symbols[kGroupSize];
|
||||
unsigned i = 0;
|
||||
do
|
||||
{
|
||||
UInt32 symbol = mtfs[mtfPos++];
|
||||
if (symbol >= 0xFF)
|
||||
symbol += mtfs[mtfPos++];
|
||||
symbols[i] = symbol;
|
||||
}
|
||||
while (++i < kGroupSize && mtfPos < mtfArraySize);
|
||||
|
||||
UInt32 bestPrice2 = 0xFFFFFFFF;
|
||||
unsigned t = 0;
|
||||
do
|
||||
{
|
||||
const Byte *lens = Lens[t];
|
||||
UInt32 price = 0;
|
||||
unsigned j = 0;
|
||||
do
|
||||
price += lens[symbols[j]];
|
||||
while (++j < i);
|
||||
if (price < bestPrice2)
|
||||
{
|
||||
m_Selectors[g] = (Byte)t;
|
||||
bestPrice2 = price;
|
||||
}
|
||||
}
|
||||
while (++t < numTables);
|
||||
UInt32 *freqs = Freqs[m_Selectors[g++]];
|
||||
unsigned j = 0;
|
||||
do
|
||||
freqs[symbols[j]]++;
|
||||
while (++j < i);
|
||||
}
|
||||
while (mtfPos < mtfArraySize);
|
||||
}
|
||||
|
||||
unsigned t = 0;
|
||||
do
|
||||
{
|
||||
UInt32 *freqs = Freqs[t];
|
||||
unsigned i = 0;
|
||||
do
|
||||
if (freqs[i] == 0)
|
||||
freqs[i] = 1;
|
||||
while (++i < alphaSize);
|
||||
Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding);
|
||||
}
|
||||
while (++t < numTables);
|
||||
}
|
||||
|
||||
{
|
||||
Byte mtfSel[kNumTablesMax];
|
||||
{
|
||||
unsigned t = 0;
|
||||
do
|
||||
mtfSel[t] = (Byte)t;
|
||||
while (++t < numTables);
|
||||
}
|
||||
|
||||
UInt32 i = 0;
|
||||
do
|
||||
{
|
||||
Byte sel = m_Selectors[i];
|
||||
unsigned pos;
|
||||
for (pos = 0; mtfSel[pos] != sel; pos++)
|
||||
WriteBit2(1);
|
||||
WriteBit2(0);
|
||||
for (; pos > 0; pos--)
|
||||
mtfSel[pos] = mtfSel[(size_t)pos - 1];
|
||||
mtfSel[0] = sel;
|
||||
}
|
||||
while (++i < numSelectors);
|
||||
}
|
||||
|
||||
{
|
||||
unsigned t = 0;
|
||||
do
|
||||
{
|
||||
const Byte *lens = Lens[t];
|
||||
UInt32 len = lens[0];
|
||||
WriteBits2(len, kNumLevelsBits);
|
||||
unsigned i = 0;
|
||||
do
|
||||
{
|
||||
UInt32 level = lens[i];
|
||||
while (len != level)
|
||||
{
|
||||
WriteBit2(1);
|
||||
if (len < level)
|
||||
{
|
||||
WriteBit2(0);
|
||||
len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteBit2(1);
|
||||
len--;
|
||||
}
|
||||
}
|
||||
WriteBit2(0);
|
||||
}
|
||||
while (++i < alphaSize);
|
||||
}
|
||||
while (++t < numTables);
|
||||
}
|
||||
|
||||
{
|
||||
UInt32 groupSize = 0;
|
||||
UInt32 groupIndex = 0;
|
||||
const Byte *lens = 0;
|
||||
const UInt32 *codes = 0;
|
||||
UInt32 mtfPos = 0;
|
||||
do
|
||||
{
|
||||
UInt32 symbol = mtfs[mtfPos++];
|
||||
if (symbol >= 0xFF)
|
||||
symbol += mtfs[mtfPos++];
|
||||
if (groupSize == 0)
|
||||
{
|
||||
groupSize = kGroupSize;
|
||||
unsigned t = m_Selectors[groupIndex++];
|
||||
lens = Lens[t];
|
||||
codes = Codes[t];
|
||||
}
|
||||
groupSize--;
|
||||
m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]);
|
||||
}
|
||||
while (mtfPos < mtfArraySize);
|
||||
}
|
||||
|
||||
if (!m_OptimizeNumTables)
|
||||
break;
|
||||
UInt32 price = m_OutStreamCurrent->GetPos() - startPos;
|
||||
if (price <= bestPrice)
|
||||
{
|
||||
if (nt == kNumTablesMax)
|
||||
break;
|
||||
bestPrice = price;
|
||||
bestNumTables = nt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blockSize > 0
|
||||
UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
|
||||
{
|
||||
WriteByte2(kBlockSig0);
|
||||
WriteByte2(kBlockSig1);
|
||||
WriteByte2(kBlockSig2);
|
||||
WriteByte2(kBlockSig3);
|
||||
WriteByte2(kBlockSig4);
|
||||
WriteByte2(kBlockSig5);
|
||||
|
||||
CBZip2Crc crc;
|
||||
unsigned numReps = 0;
|
||||
Byte prevByte = block[0];
|
||||
UInt32 i = 0;
|
||||
do
|
||||
{
|
||||
Byte b = block[i];
|
||||
if (numReps == kRleModeRepSize)
|
||||
{
|
||||
for (; b > 0; b--)
|
||||
crc.UpdateByte(prevByte);
|
||||
numReps = 0;
|
||||
continue;
|
||||
}
|
||||
if (prevByte == b)
|
||||
numReps++;
|
||||
else
|
||||
{
|
||||
numReps = 1;
|
||||
prevByte = b;
|
||||
}
|
||||
crc.UpdateByte(b);
|
||||
}
|
||||
while (++i < blockSize);
|
||||
UInt32 crcRes = crc.GetDigest();
|
||||
WriteCrc2(crcRes);
|
||||
EncodeBlock(block, blockSize);
|
||||
return crcRes;
|
||||
}
|
||||
|
||||
void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
|
||||
{
|
||||
UInt32 numCrcs = m_NumCrcs;
|
||||
bool needCompare = false;
|
||||
|
||||
UInt32 startBytePos = m_OutStreamCurrent->GetBytePos();
|
||||
UInt32 startPos = m_OutStreamCurrent->GetPos();
|
||||
Byte startCurByte = m_OutStreamCurrent->GetCurByte();
|
||||
Byte endCurByte = 0;
|
||||
UInt32 endPos = 0;
|
||||
if (numPasses > 1 && blockSize >= (1 << 10))
|
||||
{
|
||||
UInt32 blockSize0 = blockSize / 2; // ????
|
||||
|
||||
for (; (block[blockSize0] == block[(size_t)blockSize0 - 1]
|
||||
|| block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2])
|
||||
&& blockSize0 < blockSize;
|
||||
blockSize0++);
|
||||
|
||||
if (blockSize0 < blockSize)
|
||||
{
|
||||
EncodeBlock2(block, blockSize0, numPasses - 1);
|
||||
EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1);
|
||||
endPos = m_OutStreamCurrent->GetPos();
|
||||
endCurByte = m_OutStreamCurrent->GetCurByte();
|
||||
if ((endPos & 7) > 0)
|
||||
WriteBits2(0, 8 - (endPos & 7));
|
||||
m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
|
||||
needCompare = true;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos();
|
||||
UInt32 startPos2 = m_OutStreamCurrent->GetPos();
|
||||
UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
|
||||
UInt32 endPos2 = m_OutStreamCurrent->GetPos();
|
||||
|
||||
if (needCompare)
|
||||
{
|
||||
UInt32 size2 = endPos2 - startPos2;
|
||||
if (size2 < endPos - startPos)
|
||||
{
|
||||
UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2;
|
||||
Byte *buffer = m_OutStreamCurrent->GetStream();
|
||||
for (UInt32 i = 0; i < numBytes; i++)
|
||||
buffer[startBytePos + i] = buffer[startBytePos2 + i];
|
||||
m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);
|
||||
m_NumCrcs = numCrcs;
|
||||
m_CRCs[m_NumCrcs++] = crcVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_OutStreamCurrent->SetPos(endPos);
|
||||
m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_NumCrcs = numCrcs;
|
||||
m_CRCs[m_NumCrcs++] = crcVal;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
|
||||
{
|
||||
CMsbfEncoderTemp outStreamTemp;
|
||||
outStreamTemp.SetStream(m_TempArray);
|
||||
outStreamTemp.Init();
|
||||
m_OutStreamCurrent = &outStreamTemp;
|
||||
|
||||
m_NumCrcs = 0;
|
||||
|
||||
EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses);
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
if (Encoder->MtMode)
|
||||
Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
|
||||
#endif
|
||||
for (UInt32 i = 0; i < m_NumCrcs; i++)
|
||||
Encoder->CombinedCrc.Update(m_CRCs[i]);
|
||||
Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte());
|
||||
HRESULT res = S_OK;
|
||||
#ifndef _7ZIP_ST
|
||||
if (Encoder->MtMode)
|
||||
{
|
||||
UInt32 blockIndex = m_BlockIndex + 1;
|
||||
if (blockIndex == Encoder->NumThreads)
|
||||
blockIndex = 0;
|
||||
|
||||
if (Encoder->Progress)
|
||||
{
|
||||
UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize();
|
||||
res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize);
|
||||
}
|
||||
|
||||
Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte)
|
||||
{
|
||||
UInt32 bytesSize = (sizeInBits >> 3);
|
||||
for (UInt32 i = 0; i < bytesSize; i++)
|
||||
m_OutStream.WriteBits(data[i], 8);
|
||||
WriteBits(lastByte, (sizeInBits & 7));
|
||||
}
|
||||
|
||||
|
||||
HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
Progress = progress;
|
||||
RINOK(Create());
|
||||
for (UInt32 t = 0; t < NumThreads; t++)
|
||||
#endif
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
CThreadInfo &ti = ThreadsInfo[t];
|
||||
if (MtMode)
|
||||
{
|
||||
RINOK(ti.StreamWasFinishedEvent.Reset());
|
||||
RINOK(ti.WaitingWasStartedEvent.Reset());
|
||||
RINOK(ti.CanWriteEvent.Reset());
|
||||
}
|
||||
#else
|
||||
CThreadInfo &ti = ThreadsInfo;
|
||||
ti.Encoder = this;
|
||||
#endif
|
||||
|
||||
ti.m_OptimizeNumTables = _props.DoOptimizeNumTables();
|
||||
|
||||
if (!ti.Alloc())
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
|
||||
if (!m_InStream.Create(kBufferSize))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!m_OutStream.Create(kBufferSize))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
|
||||
m_InStream.SetStream(inStream);
|
||||
m_InStream.Init();
|
||||
|
||||
m_OutStream.SetStream(outStream);
|
||||
m_OutStream.Init();
|
||||
|
||||
CombinedCrc.Init();
|
||||
#ifndef _7ZIP_ST
|
||||
NextBlockIndex = 0;
|
||||
StreamWasFinished = false;
|
||||
CloseThreads = false;
|
||||
CanStartWaitingEvent.Reset();
|
||||
#endif
|
||||
|
||||
WriteByte(kArSig0);
|
||||
WriteByte(kArSig1);
|
||||
WriteByte(kArSig2);
|
||||
WriteByte((Byte)(kArSig3 + _props.BlockSizeMult));
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
|
||||
if (MtMode)
|
||||
{
|
||||
ThreadsInfo[0].CanWriteEvent.Set();
|
||||
Result = S_OK;
|
||||
CanProcessEvent.Set();
|
||||
UInt32 t;
|
||||
for (t = 0; t < NumThreads; t++)
|
||||
ThreadsInfo[t].StreamWasFinishedEvent.Lock();
|
||||
CanProcessEvent.Reset();
|
||||
CanStartWaitingEvent.Set();
|
||||
for (t = 0; t < NumThreads; t++)
|
||||
ThreadsInfo[t].WaitingWasStartedEvent.Lock();
|
||||
CanStartWaitingEvent.Reset();
|
||||
RINOK(Result);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
CThreadInfo &ti =
|
||||
#ifndef _7ZIP_ST
|
||||
ThreadsInfo[0];
|
||||
#else
|
||||
ThreadsInfo;
|
||||
#endif
|
||||
UInt32 blockSize = ReadRleBlock(ti.m_Block);
|
||||
if (blockSize == 0)
|
||||
break;
|
||||
RINOK(ti.EncodeBlock3(blockSize));
|
||||
if (progress)
|
||||
{
|
||||
UInt64 packSize = m_InStream.GetProcessedSize();
|
||||
UInt64 unpackSize = m_OutStream.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteByte(kFinSig0);
|
||||
WriteByte(kFinSig1);
|
||||
WriteByte(kFinSig2);
|
||||
WriteByte(kFinSig3);
|
||||
WriteByte(kFinSig4);
|
||||
WriteByte(kFinSig5);
|
||||
|
||||
WriteCrc(CombinedCrc.GetDigest());
|
||||
return Flush();
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::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 COutBufferException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
|
||||
{
|
||||
int level = -1;
|
||||
CEncProps props;
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = coderProps[i];
|
||||
PROPID propID = propIDs[i];
|
||||
if (propID >= NCoderPropID::kReduceSize)
|
||||
continue;
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
UInt32 v = (UInt32)prop.ulVal;
|
||||
switch (propID)
|
||||
{
|
||||
case NCoderPropID::kNumPasses: props.NumPasses = v; break;
|
||||
case NCoderPropID::kDictionarySize: props.BlockSizeMult = v / kBlockSizeStep; break;
|
||||
case NCoderPropID::kLevel: level = v; break;
|
||||
case NCoderPropID::kNumThreads:
|
||||
{
|
||||
#ifndef _7ZIP_ST
|
||||
SetNumberOfThreads(v);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
props.Normalize(level);
|
||||
_props = props;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
STDMETHODIMP CEncoder::SetNumberOfThreads(UInt32 numThreads)
|
||||
{
|
||||
const UInt32 kNumThreadsMax = 64;
|
||||
if (numThreads < 1) numThreads = 1;
|
||||
if (numThreads > kNumThreadsMax) numThreads = kNumThreadsMax;
|
||||
NumThreads = numThreads;
|
||||
return S_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,239 @@
|
||||
// BZip2Encoder.h
|
||||
|
||||
#ifndef __COMPRESS_BZIP2_ENCODER_H
|
||||
#define __COMPRESS_BZIP2_ENCODER_H
|
||||
|
||||
#include "../../Common/Defs.h"
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
#include "../../Windows/Synchronization.h"
|
||||
#include "../../Windows/Thread.h"
|
||||
#endif
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
#include "../Common/OutBuffer.h"
|
||||
|
||||
#include "BitmEncoder.h"
|
||||
#include "BZip2Const.h"
|
||||
#include "BZip2Crc.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBZip2 {
|
||||
|
||||
class CMsbfEncoderTemp
|
||||
{
|
||||
UInt32 _pos;
|
||||
unsigned _bitPos;
|
||||
Byte _curByte;
|
||||
Byte *_buf;
|
||||
public:
|
||||
void SetStream(Byte *buf) { _buf = buf; }
|
||||
Byte *GetStream() const { return _buf; }
|
||||
|
||||
void Init()
|
||||
{
|
||||
_pos = 0;
|
||||
_bitPos = 8;
|
||||
_curByte = 0;
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
if (_bitPos < 8)
|
||||
WriteBits(0, _bitPos);
|
||||
}
|
||||
|
||||
void WriteBits(UInt32 value, unsigned numBits)
|
||||
{
|
||||
while (numBits > 0)
|
||||
{
|
||||
unsigned numNewBits = MyMin(numBits, _bitPos);
|
||||
numBits -= numNewBits;
|
||||
|
||||
_curByte <<= numNewBits;
|
||||
UInt32 newBits = value >> numBits;
|
||||
_curByte |= Byte(newBits);
|
||||
value -= (newBits << numBits);
|
||||
|
||||
_bitPos -= numNewBits;
|
||||
|
||||
if (_bitPos == 0)
|
||||
{
|
||||
_buf[_pos++] = _curByte;
|
||||
_bitPos = 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 GetBytePos() const { return _pos ; }
|
||||
UInt32 GetPos() const { return _pos * 8 + (8 - _bitPos); }
|
||||
Byte GetCurByte() const { return _curByte; }
|
||||
void SetPos(UInt32 bitPos)
|
||||
{
|
||||
_pos = bitPos >> 3;
|
||||
_bitPos = 8 - ((unsigned)bitPos & 7);
|
||||
}
|
||||
void SetCurState(unsigned bitPos, Byte curByte)
|
||||
{
|
||||
_bitPos = 8 - bitPos;
|
||||
_curByte = curByte;
|
||||
}
|
||||
};
|
||||
|
||||
class CEncoder;
|
||||
|
||||
const unsigned kNumPassesMax = 10;
|
||||
|
||||
class CThreadInfo
|
||||
{
|
||||
public:
|
||||
Byte *m_Block;
|
||||
private:
|
||||
Byte *m_MtfArray;
|
||||
Byte *m_TempArray;
|
||||
UInt32 *m_BlockSorterIndex;
|
||||
|
||||
CMsbfEncoderTemp *m_OutStreamCurrent;
|
||||
|
||||
Byte Lens[kNumTablesMax][kMaxAlphaSize];
|
||||
UInt32 Freqs[kNumTablesMax][kMaxAlphaSize];
|
||||
UInt32 Codes[kNumTablesMax][kMaxAlphaSize];
|
||||
|
||||
Byte m_Selectors[kNumSelectorsMax];
|
||||
|
||||
UInt32 m_CRCs[1 << kNumPassesMax];
|
||||
UInt32 m_NumCrcs;
|
||||
|
||||
UInt32 m_BlockIndex;
|
||||
|
||||
void WriteBits2(UInt32 value, unsigned numBits);
|
||||
void WriteByte2(Byte b);
|
||||
void WriteBit2(Byte v);
|
||||
void WriteCrc2(UInt32 v);
|
||||
|
||||
void EncodeBlock(const Byte *block, UInt32 blockSize);
|
||||
UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize);
|
||||
void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses);
|
||||
public:
|
||||
bool m_OptimizeNumTables;
|
||||
CEncoder *Encoder;
|
||||
#ifndef _7ZIP_ST
|
||||
NWindows::CThread Thread;
|
||||
|
||||
NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
|
||||
NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent;
|
||||
|
||||
// it's not member of this thread. We just need one event per thread
|
||||
NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
|
||||
|
||||
UInt64 m_PackSize;
|
||||
|
||||
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
|
||||
HRESULT Create();
|
||||
void FinishStream(bool needLeave);
|
||||
DWORD ThreadFunc();
|
||||
#endif
|
||||
|
||||
CThreadInfo(): m_BlockSorterIndex(0), m_Block(0) {}
|
||||
~CThreadInfo() { Free(); }
|
||||
bool Alloc();
|
||||
void Free();
|
||||
|
||||
HRESULT EncodeBlock3(UInt32 blockSize);
|
||||
};
|
||||
|
||||
struct CEncProps
|
||||
{
|
||||
UInt32 BlockSizeMult;
|
||||
UInt32 NumPasses;
|
||||
|
||||
CEncProps()
|
||||
{
|
||||
BlockSizeMult = (UInt32)(Int32)-1;
|
||||
NumPasses = (UInt32)(Int32)-1;
|
||||
}
|
||||
void Normalize(int level);
|
||||
bool DoOptimizeNumTables() const { return NumPasses > 1; }
|
||||
};
|
||||
|
||||
class CEncoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
#ifndef _7ZIP_ST
|
||||
public ICompressSetCoderMt,
|
||||
#endif
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt32 m_NumThreadsPrev;
|
||||
public:
|
||||
CInBuffer m_InStream;
|
||||
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
|
||||
CBitmEncoder<COutBuffer> m_OutStream;
|
||||
CEncProps _props;
|
||||
CBZip2CombinedCrc CombinedCrc;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
CThreadInfo *ThreadsInfo;
|
||||
NWindows::NSynchronization::CManualResetEvent CanProcessEvent;
|
||||
NWindows::NSynchronization::CCriticalSection CS;
|
||||
UInt32 NumThreads;
|
||||
bool MtMode;
|
||||
UInt32 NextBlockIndex;
|
||||
|
||||
bool CloseThreads;
|
||||
bool StreamWasFinished;
|
||||
NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
|
||||
|
||||
HRESULT Result;
|
||||
ICompressProgressInfo *Progress;
|
||||
#else
|
||||
CThreadInfo ThreadsInfo;
|
||||
#endif
|
||||
|
||||
UInt32 ReadRleBlock(Byte *buf);
|
||||
void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte);
|
||||
|
||||
void WriteBits(UInt32 value, unsigned numBits);
|
||||
void WriteByte(Byte b);
|
||||
// void WriteBit(Byte v);
|
||||
void WriteCrc(UInt32 v);
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
HRESULT Create();
|
||||
void Free();
|
||||
#endif
|
||||
|
||||
public:
|
||||
CEncoder();
|
||||
#ifndef _7ZIP_ST
|
||||
~CEncoder();
|
||||
#endif
|
||||
|
||||
HRESULT Flush() { return m_OutStream.Flush(); }
|
||||
|
||||
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
|
||||
#ifndef _7ZIP_ST
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
|
||||
#endif
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetCoderProperties)
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
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(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
|
||||
#endif
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
// BZip2Register.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "BZip2Decoder.h"
|
||||
#if !defined(EXTRACT_ONLY) && !defined(BZIP2_EXTRACT_ONLY)
|
||||
#include "BZip2Encoder.h"
|
||||
#endif
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBZip2 {
|
||||
|
||||
REGISTER_CODEC_CREATE(CreateDec, CDecoder)
|
||||
|
||||
#if !defined(EXTRACT_ONLY) && !defined(BZIP2_EXTRACT_ONLY)
|
||||
REGISTER_CODEC_CREATE(CreateEnc, CEncoder)
|
||||
#else
|
||||
#define CreateEnc NULL
|
||||
#endif
|
||||
|
||||
REGISTER_CODEC_2(BZip2, CreateDec, CreateEnc, 0x40202, "BZip2")
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,666 @@
|
||||
// Bcj2Coder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "Bcj2Coder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBcj2 {
|
||||
|
||||
CBaseCoder::CBaseCoder()
|
||||
{
|
||||
for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
|
||||
{
|
||||
_bufs[i] = NULL;
|
||||
_bufsCurSizes[i] = 0;
|
||||
_bufsNewSizes[i] = (1 << 18);
|
||||
}
|
||||
}
|
||||
|
||||
CBaseCoder::~CBaseCoder()
|
||||
{
|
||||
for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
|
||||
::MidFree(_bufs[i]);
|
||||
}
|
||||
|
||||
HRESULT CBaseCoder::Alloc(bool allocForOrig)
|
||||
{
|
||||
unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
{
|
||||
UInt32 newSize = _bufsNewSizes[i];
|
||||
const UInt32 kMinBufSize = 1;
|
||||
if (newSize < kMinBufSize)
|
||||
newSize = kMinBufSize;
|
||||
if (!_bufs[i] || newSize != _bufsCurSizes[i])
|
||||
{
|
||||
if (_bufs[i])
|
||||
{
|
||||
::MidFree(_bufs[i]);
|
||||
_bufs[i] = 0;
|
||||
}
|
||||
_bufsCurSizes[i] = 0;
|
||||
Byte *buf = (Byte *)::MidAlloc(newSize);
|
||||
_bufs[i] = buf;
|
||||
if (!buf)
|
||||
return E_OUTOFMEMORY;
|
||||
_bufsCurSizes[i] = newSize;
|
||||
}
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
|
||||
CEncoder::CEncoder(): _relatLim(BCJ2_RELAT_LIMIT) {}
|
||||
CEncoder::~CEncoder() {}
|
||||
|
||||
STDMETHODIMP CEncoder::SetInBufSize(UInt32, UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
|
||||
STDMETHODIMP CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
|
||||
{
|
||||
UInt32 relatLim = BCJ2_RELAT_LIMIT;
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = props[i];
|
||||
PROPID propID = propIDs[i];
|
||||
if (propID >= NCoderPropID::kReduceSize)
|
||||
continue;
|
||||
switch (propID)
|
||||
{
|
||||
/*
|
||||
case NCoderPropID::kDefaultProp:
|
||||
{
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
UInt32 v = prop.ulVal;
|
||||
if (v > 31)
|
||||
return E_INVALIDARG;
|
||||
relatLim = (UInt32)1 << v;
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case NCoderPropID::kDictionarySize:
|
||||
{
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
relatLim = prop.ulVal;
|
||||
if (relatLim > ((UInt32)1 << 31))
|
||||
return E_INVALIDARG;
|
||||
break;
|
||||
}
|
||||
|
||||
case NCoderPropID::kNumThreads:
|
||||
continue;
|
||||
case NCoderPropID::kLevel:
|
||||
continue;
|
||||
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
|
||||
_relatLim = relatLim;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CEncoder::CodeReal(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
|
||||
ISequentialOutStream * const *outStreams, const UInt64 * const * /* outSizes */, UInt32 numOutStreams,
|
||||
ICompressProgressInfo *progress)
|
||||
{
|
||||
if (numInStreams != 1 || numOutStreams != BCJ2_NUM_STREAMS)
|
||||
return E_INVALIDARG;
|
||||
|
||||
RINOK(Alloc());
|
||||
|
||||
UInt32 fileSize_for_Conv = 0;
|
||||
if (inSizes && inSizes[0])
|
||||
{
|
||||
UInt64 inSize = *inSizes[0];
|
||||
if (inSize <= BCJ2_FileSize_MAX)
|
||||
fileSize_for_Conv = (UInt32)inSize;
|
||||
}
|
||||
|
||||
CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
|
||||
inStreams[0]->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
|
||||
|
||||
CBcj2Enc enc;
|
||||
|
||||
enc.src = _bufs[BCJ2_NUM_STREAMS];
|
||||
enc.srcLim = enc.src;
|
||||
|
||||
{
|
||||
for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
|
||||
{
|
||||
enc.bufs[i] = _bufs[i];
|
||||
enc.lims[i] = _bufs[i] + _bufsCurSizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
size_t numBytes_in_ReadBuf = 0;
|
||||
UInt64 prevProgress = 0;
|
||||
UInt64 totalStreamRead = 0; // size read from InputStream
|
||||
UInt64 currentInPos = 0; // data that was processed, it doesn't include data in input buffer and data in enc.temp
|
||||
UInt64 outSizeRc = 0;
|
||||
|
||||
Bcj2Enc_Init(&enc);
|
||||
|
||||
enc.fileIp = 0;
|
||||
enc.fileSize = fileSize_for_Conv;
|
||||
|
||||
enc.relatLimit = _relatLim;
|
||||
|
||||
enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
|
||||
|
||||
bool needSubSize = false;
|
||||
UInt64 subStreamIndex = 0;
|
||||
UInt64 subStreamStartPos = 0;
|
||||
bool readWasFinished = false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (needSubSize && getSubStreamSize)
|
||||
{
|
||||
enc.fileIp = 0;
|
||||
enc.fileSize = fileSize_for_Conv;
|
||||
enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
UInt64 subStreamSize = 0;
|
||||
HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
|
||||
needSubSize = false;
|
||||
|
||||
if (result == S_OK)
|
||||
{
|
||||
UInt64 newEndPos = subStreamStartPos + subStreamSize;
|
||||
|
||||
bool isAccurateEnd = (newEndPos < totalStreamRead ||
|
||||
(newEndPos <= totalStreamRead && readWasFinished));
|
||||
|
||||
if (newEndPos <= currentInPos && isAccurateEnd)
|
||||
{
|
||||
subStreamStartPos = newEndPos;
|
||||
subStreamIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
|
||||
|
||||
if (isAccurateEnd)
|
||||
{
|
||||
// data in enc.temp is possible here
|
||||
size_t rem = (size_t)(totalStreamRead - newEndPos);
|
||||
|
||||
/* Pos_of(enc.src) <= old newEndPos <= newEndPos
|
||||
in another case, it's fail in some code */
|
||||
if ((size_t)(enc.srcLim - enc.src) < rem)
|
||||
return E_FAIL;
|
||||
|
||||
enc.srcLim -= rem;
|
||||
enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK;
|
||||
}
|
||||
|
||||
if (subStreamSize <= BCJ2_FileSize_MAX)
|
||||
{
|
||||
enc.fileIp = enc.ip + (UInt32)(subStreamStartPos - currentInPos);
|
||||
enc.fileSize = (UInt32)subStreamSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == S_FALSE)
|
||||
break;
|
||||
if (result == E_NOTIMPL)
|
||||
{
|
||||
getSubStreamSize.Release();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (readWasFinished && totalStreamRead - currentInPos == Bcj2Enc_Get_InputData_Size(&enc))
|
||||
enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM;
|
||||
|
||||
Bcj2Enc_Encode(&enc);
|
||||
|
||||
currentInPos = totalStreamRead - numBytes_in_ReadBuf + (enc.src - _bufs[BCJ2_NUM_STREAMS]) - enc.tempPos;
|
||||
|
||||
if (Bcj2Enc_IsFinished(&enc))
|
||||
break;
|
||||
|
||||
if (enc.state < BCJ2_NUM_STREAMS)
|
||||
{
|
||||
size_t curSize = enc.bufs[enc.state] - _bufs[enc.state];
|
||||
// printf("Write stream = %2d %6d\n", enc.state, curSize);
|
||||
RINOK(WriteStream(outStreams[enc.state], _bufs[enc.state], curSize));
|
||||
if (enc.state == BCJ2_STREAM_RC)
|
||||
outSizeRc += curSize;
|
||||
|
||||
enc.bufs[enc.state] = _bufs[enc.state];
|
||||
enc.lims[enc.state] = _bufs[enc.state] + _bufsCurSizes[enc.state];
|
||||
}
|
||||
else if (enc.state != BCJ2_ENC_STATE_ORIG)
|
||||
return E_FAIL;
|
||||
else
|
||||
{
|
||||
needSubSize = true;
|
||||
|
||||
if (numBytes_in_ReadBuf != (size_t)(enc.src - _bufs[BCJ2_NUM_STREAMS]))
|
||||
{
|
||||
enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (readWasFinished)
|
||||
continue;
|
||||
|
||||
numBytes_in_ReadBuf = 0;
|
||||
enc.src = _bufs[BCJ2_NUM_STREAMS];
|
||||
enc.srcLim = _bufs[BCJ2_NUM_STREAMS];
|
||||
|
||||
UInt32 curSize = _bufsCurSizes[BCJ2_NUM_STREAMS];
|
||||
RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize));
|
||||
|
||||
// printf("Read %6d bytes\n", curSize);
|
||||
if (curSize == 0)
|
||||
{
|
||||
readWasFinished = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
numBytes_in_ReadBuf = curSize;
|
||||
totalStreamRead += numBytes_in_ReadBuf;
|
||||
enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
|
||||
}
|
||||
|
||||
if (progress && currentInPos - prevProgress >= (1 << 20))
|
||||
{
|
||||
UInt64 outSize2 = currentInPos + outSizeRc + enc.bufs[BCJ2_STREAM_RC] - enc.bufs[BCJ2_STREAM_RC];
|
||||
prevProgress = currentInPos;
|
||||
// printf("progress %8d, %8d\n", (int)inSize2, (int)outSize2);
|
||||
RINOK(progress->SetRatioInfo(¤tInPos, &outSize2));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
|
||||
{
|
||||
RINOK(WriteStream(outStreams[i], _bufs[i], enc.bufs[i] - _bufs[i]));
|
||||
}
|
||||
|
||||
// if (currentInPos != subStreamStartPos + subStreamSize) return E_FAIL;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
|
||||
ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
|
||||
ICompressProgressInfo *progress)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
|
||||
}
|
||||
catch(...) { return E_FAIL; }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
|
||||
STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
|
||||
|
||||
CDecoder::CDecoder(): _finishMode(false), _outSizeDefined(false), _outSize(0)
|
||||
{}
|
||||
|
||||
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
|
||||
{
|
||||
_finishMode = (finishMode != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CDecoder::InitCommon()
|
||||
{
|
||||
{
|
||||
for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
|
||||
dec.lims[i] = dec.bufs[i] = _bufs[i];
|
||||
}
|
||||
|
||||
{
|
||||
for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
|
||||
{
|
||||
_extraReadSizes[i] = 0;
|
||||
_inStreamsProcessed[i] = 0;
|
||||
_readRes[i] = S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
Bcj2Dec_Init(&dec);
|
||||
}
|
||||
|
||||
HRESULT CDecoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
|
||||
ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
|
||||
ICompressProgressInfo *progress)
|
||||
{
|
||||
if (numInStreams != BCJ2_NUM_STREAMS || numOutStreams != 1)
|
||||
return E_INVALIDARG;
|
||||
|
||||
RINOK(Alloc());
|
||||
|
||||
InitCommon();
|
||||
|
||||
dec.destLim = dec.dest = _bufs[BCJ2_NUM_STREAMS];
|
||||
|
||||
UInt64 outSizeProcessed = 0;
|
||||
UInt64 prevProgress = 0;
|
||||
|
||||
HRESULT res = S_OK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (Bcj2Dec_Decode(&dec) != SZ_OK)
|
||||
return S_FALSE;
|
||||
|
||||
if (dec.state < BCJ2_NUM_STREAMS)
|
||||
{
|
||||
size_t totalRead = _extraReadSizes[dec.state];
|
||||
{
|
||||
Byte *buf = _bufs[dec.state];
|
||||
for (size_t i = 0; i < totalRead; i++)
|
||||
buf[i] = dec.bufs[dec.state][i];
|
||||
dec.lims[dec.state] =
|
||||
dec.bufs[dec.state] = buf;
|
||||
}
|
||||
|
||||
if (_readRes[dec.state] != S_OK)
|
||||
{
|
||||
res = _readRes[dec.state];
|
||||
break;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;
|
||||
/*
|
||||
we want to call Read even even if size is 0
|
||||
if (inSizes && inSizes[dec.state])
|
||||
{
|
||||
UInt64 rem = *inSizes[dec.state] - _inStreamsProcessed[dec.state];
|
||||
if (curSize > rem)
|
||||
curSize = (UInt32)rem;
|
||||
}
|
||||
*/
|
||||
|
||||
HRESULT res2 = inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);
|
||||
_readRes[dec.state] = res2;
|
||||
if (curSize == 0)
|
||||
break;
|
||||
_inStreamsProcessed[dec.state] += curSize;
|
||||
totalRead += curSize;
|
||||
if (res2 != S_OK)
|
||||
break;
|
||||
}
|
||||
while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));
|
||||
|
||||
if (_readRes[dec.state] != S_OK)
|
||||
res = _readRes[dec.state];
|
||||
|
||||
if (totalRead == 0)
|
||||
break;
|
||||
|
||||
// res == S_OK;
|
||||
|
||||
if (BCJ2_IS_32BIT_STREAM(dec.state))
|
||||
{
|
||||
unsigned extraSize = ((unsigned)totalRead & 3);
|
||||
_extraReadSizes[dec.state] = extraSize;
|
||||
if (totalRead < 4)
|
||||
{
|
||||
res = (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;
|
||||
break;
|
||||
}
|
||||
totalRead -= extraSize;
|
||||
}
|
||||
|
||||
dec.lims[dec.state] = _bufs[dec.state] + totalRead;
|
||||
}
|
||||
else // if (dec.state <= BCJ2_STATE_ORIG)
|
||||
{
|
||||
size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];
|
||||
if (curSize != 0)
|
||||
{
|
||||
outSizeProcessed += curSize;
|
||||
RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));
|
||||
}
|
||||
dec.dest = _bufs[BCJ2_NUM_STREAMS];
|
||||
{
|
||||
size_t rem = _bufsCurSizes[BCJ2_NUM_STREAMS];
|
||||
if (outSizes && outSizes[0])
|
||||
{
|
||||
UInt64 outSize = *outSizes[0] - outSizeProcessed;
|
||||
if (rem > outSize)
|
||||
rem = (size_t)outSize;
|
||||
}
|
||||
dec.destLim = dec.dest + rem;
|
||||
if (rem == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
{
|
||||
const UInt64 outSize2 = outSizeProcessed + (dec.dest - _bufs[BCJ2_NUM_STREAMS]);
|
||||
if (outSize2 - prevProgress >= (1 << 22))
|
||||
{
|
||||
const UInt64 inSize2 = outSize2 + _inStreamsProcessed[BCJ2_STREAM_RC] - (dec.lims[BCJ2_STREAM_RC] - dec.bufs[BCJ2_STREAM_RC]);
|
||||
RINOK(progress->SetRatioInfo(&inSize2, &outSize2));
|
||||
prevProgress = outSize2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];
|
||||
if (curSize != 0)
|
||||
{
|
||||
outSizeProcessed += curSize;
|
||||
RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));
|
||||
}
|
||||
|
||||
if (res != S_OK)
|
||||
return res;
|
||||
|
||||
if (_finishMode)
|
||||
{
|
||||
if (!Bcj2Dec_IsFinished(&dec))
|
||||
return S_FALSE;
|
||||
|
||||
// we still allow the cases when input streams are larger than required for decoding.
|
||||
// so the case (dec.state == BCJ2_STATE_ORIG) is also allowed, if MAIN stream is larger than required.
|
||||
if (dec.state != BCJ2_STREAM_MAIN &&
|
||||
dec.state != BCJ2_DEC_STATE_ORIG)
|
||||
return S_FALSE;
|
||||
|
||||
if (inSizes)
|
||||
{
|
||||
for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
|
||||
{
|
||||
size_t rem = dec.lims[i] - dec.bufs[i] + _extraReadSizes[i];
|
||||
/*
|
||||
if (rem != 0)
|
||||
return S_FALSE;
|
||||
*/
|
||||
if (inSizes[i] && *inSizes[i] != _inStreamsProcessed[i] - rem)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)
|
||||
{
|
||||
_inStreams[streamIndex] = inStream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::ReleaseInStream2(UInt32 streamIndex)
|
||||
{
|
||||
_inStreams[streamIndex].Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
||||
{
|
||||
_outSizeDefined = (outSize != NULL);
|
||||
_outSize = 0;
|
||||
if (_outSizeDefined)
|
||||
_outSize = *outSize;
|
||||
|
||||
_outSize_Processed = 0;
|
||||
|
||||
HRESULT res = Alloc(false);
|
||||
|
||||
InitCommon();
|
||||
dec.destLim = dec.dest = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
|
||||
UInt32 totalProcessed = 0;
|
||||
|
||||
if (_outSizeDefined)
|
||||
{
|
||||
UInt64 rem = _outSize - _outSize_Processed;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
}
|
||||
dec.dest = (Byte *)data;
|
||||
dec.destLim = (const Byte *)data + size;
|
||||
|
||||
HRESULT res = S_OK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
SRes sres = Bcj2Dec_Decode(&dec);
|
||||
if (sres != SZ_OK)
|
||||
return S_FALSE;
|
||||
|
||||
{
|
||||
UInt32 curSize = (UInt32)(dec.dest - (Byte *)data);
|
||||
if (curSize != 0)
|
||||
{
|
||||
totalProcessed += curSize;
|
||||
if (processedSize)
|
||||
*processedSize = totalProcessed;
|
||||
data = (void *)((Byte *)data + curSize);
|
||||
size -= curSize;
|
||||
_outSize_Processed += curSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (dec.state >= BCJ2_NUM_STREAMS)
|
||||
break;
|
||||
|
||||
{
|
||||
size_t totalRead = _extraReadSizes[dec.state];
|
||||
{
|
||||
Byte *buf = _bufs[dec.state];
|
||||
for (size_t i = 0; i < totalRead; i++)
|
||||
buf[i] = dec.bufs[dec.state][i];
|
||||
dec.lims[dec.state] =
|
||||
dec.bufs[dec.state] = buf;
|
||||
}
|
||||
|
||||
if (_readRes[dec.state] != S_OK)
|
||||
return _readRes[dec.state];
|
||||
|
||||
do
|
||||
{
|
||||
UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;
|
||||
HRESULT res2 = _inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);
|
||||
_readRes[dec.state] = res2;
|
||||
if (curSize == 0)
|
||||
break;
|
||||
_inStreamsProcessed[dec.state] += curSize;
|
||||
totalRead += curSize;
|
||||
if (res2 != S_OK)
|
||||
break;
|
||||
}
|
||||
while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));
|
||||
|
||||
if (totalRead == 0)
|
||||
{
|
||||
if (totalProcessed == 0)
|
||||
res = _readRes[dec.state];
|
||||
break;
|
||||
}
|
||||
|
||||
if (BCJ2_IS_32BIT_STREAM(dec.state))
|
||||
{
|
||||
unsigned extraSize = ((unsigned)totalRead & 3);
|
||||
_extraReadSizes[dec.state] = extraSize;
|
||||
if (totalRead < 4)
|
||||
{
|
||||
if (totalProcessed != 0)
|
||||
return S_OK;
|
||||
return (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;
|
||||
}
|
||||
totalRead -= extraSize;
|
||||
}
|
||||
|
||||
dec.lims[dec.state] = _bufs[dec.state] + totalRead;
|
||||
}
|
||||
}
|
||||
|
||||
if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed)
|
||||
{
|
||||
if (!Bcj2Dec_IsFinished(&dec))
|
||||
return S_FALSE;
|
||||
|
||||
if (dec.state != BCJ2_STREAM_MAIN &&
|
||||
dec.state != BCJ2_DEC_STATE_ORIG)
|
||||
return S_FALSE;
|
||||
|
||||
/*
|
||||
for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
|
||||
if (dec.bufs[i] != dec.lims[i] || _extraReadSizes[i] != 0)
|
||||
return S_FALSE;
|
||||
*/
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)
|
||||
{
|
||||
const size_t rem = dec.lims[streamIndex] - dec.bufs[streamIndex] + _extraReadSizes[streamIndex];
|
||||
*value = _inStreamsProcessed[streamIndex] - rem;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,120 @@
|
||||
// Bcj2Coder.h
|
||||
|
||||
#ifndef __COMPRESS_BCJ2_CODER_H
|
||||
#define __COMPRESS_BCJ2_CODER_H
|
||||
|
||||
#include "../../../C/Bcj2.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBcj2 {
|
||||
|
||||
class CBaseCoder
|
||||
{
|
||||
protected:
|
||||
Byte *_bufs[BCJ2_NUM_STREAMS + 1];
|
||||
UInt32 _bufsCurSizes[BCJ2_NUM_STREAMS + 1];
|
||||
UInt32 _bufsNewSizes[BCJ2_NUM_STREAMS + 1];
|
||||
|
||||
HRESULT Alloc(bool allocForOrig = true);
|
||||
public:
|
||||
CBaseCoder();
|
||||
~CBaseCoder();
|
||||
};
|
||||
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
|
||||
class CEncoder:
|
||||
public ICompressCoder2,
|
||||
public ICompressSetCoderProperties,
|
||||
public ICompressSetBufSize,
|
||||
public CMyUnknownImp,
|
||||
public CBaseCoder
|
||||
{
|
||||
UInt32 _relatLim;
|
||||
|
||||
HRESULT CodeReal(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
|
||||
ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
|
||||
ICompressProgressInfo *progress);
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP3(ICompressCoder2, ICompressSetCoderProperties, ICompressSetBufSize)
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
|
||||
ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
|
||||
ICompressProgressInfo *progress);
|
||||
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
|
||||
STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
|
||||
STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
|
||||
|
||||
CEncoder();
|
||||
~CEncoder();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder2,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize2,
|
||||
public ICompressSetInStream2,
|
||||
public ISequentialInStream,
|
||||
public ICompressSetOutStreamSize,
|
||||
public ICompressSetBufSize,
|
||||
public CMyUnknownImp,
|
||||
public CBaseCoder
|
||||
{
|
||||
unsigned _extraReadSizes[BCJ2_NUM_STREAMS];
|
||||
UInt64 _inStreamsProcessed[BCJ2_NUM_STREAMS];
|
||||
HRESULT _readRes[BCJ2_NUM_STREAMS];
|
||||
CMyComPtr<ISequentialInStream> _inStreams[BCJ2_NUM_STREAMS];
|
||||
|
||||
bool _finishMode;
|
||||
bool _outSizeDefined;
|
||||
UInt64 _outSize;
|
||||
UInt64 _outSize_Processed;
|
||||
CBcj2Dec dec;
|
||||
|
||||
void InitCommon();
|
||||
// HRESULT ReadSpec();
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP7(
|
||||
ICompressCoder2,
|
||||
ICompressSetFinishMode,
|
||||
ICompressGetInStreamProcessedSize2,
|
||||
ICompressSetInStream2,
|
||||
ISequentialInStream,
|
||||
ICompressSetOutStreamSize,
|
||||
ICompressSetBufSize
|
||||
);
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
|
||||
ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
|
||||
ICompressProgressInfo *progress);
|
||||
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize2)(UInt32 streamIndex, UInt64 *value);
|
||||
|
||||
STDMETHOD(SetInStream2)(UInt32 streamIndex, ISequentialInStream *inStream);
|
||||
STDMETHOD(ReleaseInStream2)(UInt32 streamIndex);
|
||||
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
|
||||
|
||||
STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
|
||||
STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
|
||||
|
||||
CDecoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
// Bcj2Register.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "Bcj2Coder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBcj2 {
|
||||
|
||||
REGISTER_CODEC_CREATE_2(CreateCodec, CDecoder(), ICompressCoder2)
|
||||
#ifndef EXTRACT_ONLY
|
||||
REGISTER_CODEC_CREATE_2(CreateCodecOut, CEncoder(), ICompressCoder2)
|
||||
#else
|
||||
#define CreateCodecOut NULL
|
||||
#endif
|
||||
|
||||
REGISTER_CODEC_VAR
|
||||
{ CreateCodec, CreateCodecOut, 0x303011B, "BCJ2", 4, false };
|
||||
|
||||
REGISTER_CODEC(BCJ2)
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,24 @@
|
||||
// BcjCoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "BcjCoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBcj {
|
||||
|
||||
STDMETHODIMP CCoder::Init()
|
||||
{
|
||||
_bufferPos = 0;
|
||||
x86_Convert_Init(_prevMask);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(UInt32) CCoder::Filter(Byte *data, UInt32 size)
|
||||
{
|
||||
UInt32 processed = (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, _encode);
|
||||
_bufferPos += processed;
|
||||
return processed;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,31 @@
|
||||
// BcjCoder.h
|
||||
|
||||
#ifndef __COMPRESS_BCJ_CODER_H
|
||||
#define __COMPRESS_BCJ_CODER_H
|
||||
|
||||
#include "../../../C/Bra.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBcj {
|
||||
|
||||
class CCoder:
|
||||
public ICompressFilter,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt32 _bufferPos;
|
||||
UInt32 _prevMask;
|
||||
int _encode;
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICompressFilter);
|
||||
INTERFACE_ICompressFilter(;)
|
||||
|
||||
CCoder(int encode): _bufferPos(0), _encode(encode) { x86_Convert_Init(_prevMask); }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
// BcjRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "BcjCoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBcj {
|
||||
|
||||
REGISTER_FILTER_E(BCJ,
|
||||
CCoder(false),
|
||||
CCoder(true),
|
||||
0x3030103, "BCJ")
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,24 @@
|
||||
// BitlDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "BitlDecoder.h"
|
||||
|
||||
namespace NBitl {
|
||||
|
||||
Byte kInvertTable[256];
|
||||
|
||||
struct CInverterTableInitializer
|
||||
{
|
||||
CInverterTableInitializer()
|
||||
{
|
||||
for (unsigned i = 0; i < 256; i++)
|
||||
{
|
||||
unsigned x = ((i & 0x55) << 1) | ((i & 0xAA) >> 1);
|
||||
x = ((x & 0x33) << 2) | ((x & 0xCC) >> 2);
|
||||
kInvertTable[i] = (Byte)(((x & 0x0F) << 4) | ((x & 0xF0) >> 4));
|
||||
}
|
||||
}
|
||||
} g_InverterTableInitializer;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
// BitlDecoder.h -- the Least Significant Bit of byte is First
|
||||
|
||||
#ifndef __BITL_DECODER_H
|
||||
#define __BITL_DECODER_H
|
||||
|
||||
#include "../IStream.h"
|
||||
|
||||
namespace NBitl {
|
||||
|
||||
const unsigned kNumBigValueBits = 8 * 4;
|
||||
const unsigned kNumValueBytes = 3;
|
||||
const unsigned kNumValueBits = 8 * kNumValueBytes;
|
||||
|
||||
const UInt32 kMask = (1 << kNumValueBits) - 1;
|
||||
|
||||
extern Byte kInvertTable[256];
|
||||
|
||||
/* TInByte must support "Extra Bytes" (bytes that can be read after the end of stream
|
||||
TInByte::ReadByte() returns 0xFF after the end of stream
|
||||
TInByte::NumExtraBytes contains the number "Extra Bytes"
|
||||
|
||||
Bitl decoder can read up to 4 bytes ahead to internal buffer. */
|
||||
|
||||
template<class TInByte>
|
||||
class CBaseDecoder
|
||||
{
|
||||
protected:
|
||||
unsigned _bitPos;
|
||||
UInt32 _value;
|
||||
TInByte _stream;
|
||||
public:
|
||||
bool Create(UInt32 bufSize) { return _stream.Create(bufSize); }
|
||||
void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream); }
|
||||
void Init()
|
||||
{
|
||||
_stream.Init();
|
||||
_bitPos = kNumBigValueBits;
|
||||
_value = 0;
|
||||
}
|
||||
|
||||
UInt64 GetStreamSize() const { return _stream.GetStreamSize(); }
|
||||
UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); }
|
||||
|
||||
bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; }
|
||||
|
||||
MY_FORCE_INLINE
|
||||
void Normalize()
|
||||
{
|
||||
for (; _bitPos >= 8; _bitPos -= 8)
|
||||
_value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value;
|
||||
}
|
||||
|
||||
MY_FORCE_INLINE
|
||||
UInt32 ReadBits(unsigned numBits)
|
||||
{
|
||||
Normalize();
|
||||
UInt32 res = _value & ((1 << numBits) - 1);
|
||||
_bitPos += numBits;
|
||||
_value >>= numBits;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool ExtraBitsWereRead() const
|
||||
{
|
||||
return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3));
|
||||
}
|
||||
|
||||
bool ExtraBitsWereRead_Fast() const
|
||||
{
|
||||
// full version is not inlined in vc6.
|
||||
// return _stream.NumExtraBytes != 0 && (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3));
|
||||
|
||||
// (_stream.NumExtraBytes > 4) is fast overread detection. It's possible that
|
||||
// it doesn't return true, if small number of extra bits were read.
|
||||
return (_stream.NumExtraBytes > 4);
|
||||
}
|
||||
|
||||
// it must be fixed !!! with extra bits
|
||||
// UInt32 GetNumExtraBytes() const { return _stream.NumExtraBytes; }
|
||||
};
|
||||
|
||||
template<class TInByte>
|
||||
class CDecoder: public CBaseDecoder<TInByte>
|
||||
{
|
||||
UInt32 _normalValue;
|
||||
|
||||
public:
|
||||
void Init()
|
||||
{
|
||||
CBaseDecoder<TInByte>::Init();
|
||||
_normalValue = 0;
|
||||
}
|
||||
|
||||
MY_FORCE_INLINE
|
||||
void Normalize()
|
||||
{
|
||||
for (; this->_bitPos >= 8; this->_bitPos -= 8)
|
||||
{
|
||||
Byte b = this->_stream.ReadByte();
|
||||
_normalValue = ((UInt32)b << (kNumBigValueBits - this->_bitPos)) | _normalValue;
|
||||
this->_value = (this->_value << 8) | kInvertTable[b];
|
||||
}
|
||||
}
|
||||
|
||||
MY_FORCE_INLINE
|
||||
UInt32 GetValue(unsigned numBits)
|
||||
{
|
||||
Normalize();
|
||||
return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits);
|
||||
}
|
||||
|
||||
MY_FORCE_INLINE
|
||||
void MovePos(unsigned numBits)
|
||||
{
|
||||
this->_bitPos += numBits;
|
||||
_normalValue >>= numBits;
|
||||
}
|
||||
|
||||
MY_FORCE_INLINE
|
||||
UInt32 ReadBits(unsigned numBits)
|
||||
{
|
||||
Normalize();
|
||||
UInt32 res = _normalValue & ((1 << numBits) - 1);
|
||||
MovePos(numBits);
|
||||
return res;
|
||||
}
|
||||
|
||||
void AlignToByte() { MovePos((32 - this->_bitPos) & 7); }
|
||||
|
||||
MY_FORCE_INLINE
|
||||
Byte ReadDirectByte() { return this->_stream.ReadByte(); }
|
||||
|
||||
MY_FORCE_INLINE
|
||||
Byte ReadAlignedByte()
|
||||
{
|
||||
if (this->_bitPos == kNumBigValueBits)
|
||||
return this->_stream.ReadByte();
|
||||
Byte b = (Byte)(_normalValue & 0xFF);
|
||||
MovePos(8);
|
||||
return b;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
// BitlEncoder.h -- the Least Significant Bit of byte is First
|
||||
|
||||
#ifndef __BITL_ENCODER_H
|
||||
#define __BITL_ENCODER_H
|
||||
|
||||
#include "../Common/OutBuffer.h"
|
||||
|
||||
class CBitlEncoder
|
||||
{
|
||||
COutBuffer _stream;
|
||||
unsigned _bitPos;
|
||||
Byte _curByte;
|
||||
public:
|
||||
bool Create(UInt32 bufSize) { return _stream.Create(bufSize); }
|
||||
void SetStream(ISequentialOutStream *outStream) { _stream.SetStream(outStream); }
|
||||
// unsigned GetBitPosition() const { return (8 - _bitPos); }
|
||||
UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() + ((8 - _bitPos + 7) >> 3); }
|
||||
void Init()
|
||||
{
|
||||
_stream.Init();
|
||||
_bitPos = 8;
|
||||
_curByte = 0;
|
||||
}
|
||||
HRESULT Flush()
|
||||
{
|
||||
FlushByte();
|
||||
return _stream.Flush();
|
||||
}
|
||||
void FlushByte()
|
||||
{
|
||||
if (_bitPos < 8)
|
||||
_stream.WriteByte(_curByte);
|
||||
_bitPos = 8;
|
||||
_curByte = 0;
|
||||
}
|
||||
void WriteBits(UInt32 value, unsigned numBits)
|
||||
{
|
||||
while (numBits > 0)
|
||||
{
|
||||
if (numBits < _bitPos)
|
||||
{
|
||||
_curByte |= (value & ((1 << numBits) - 1)) << (8 - _bitPos);
|
||||
_bitPos -= numBits;
|
||||
return;
|
||||
}
|
||||
numBits -= _bitPos;
|
||||
_stream.WriteByte((Byte)(_curByte | (value << (8 - _bitPos))));
|
||||
value >>= _bitPos;
|
||||
_bitPos = 8;
|
||||
_curByte = 0;
|
||||
}
|
||||
}
|
||||
void WriteByte(Byte b) { _stream.WriteByte(b);}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
// BitmDecoder.h -- the Most Significant Bit of byte is First
|
||||
|
||||
#ifndef __BITM_DECODER_H
|
||||
#define __BITM_DECODER_H
|
||||
|
||||
#include "../IStream.h"
|
||||
|
||||
namespace NBitm {
|
||||
|
||||
const unsigned kNumBigValueBits = 8 * 4;
|
||||
const unsigned kNumValueBytes = 3;
|
||||
const unsigned kNumValueBits = 8 * kNumValueBytes;
|
||||
|
||||
const UInt32 kMask = (1 << kNumValueBits) - 1;
|
||||
|
||||
// _bitPos - the number of free bits (high bits in _value)
|
||||
// (kNumBigValueBits - _bitPos) = (32 - _bitPos) == the number of ready to read bits (low bits of _value)
|
||||
|
||||
template<class TInByte>
|
||||
class CDecoder
|
||||
{
|
||||
unsigned _bitPos;
|
||||
UInt32 _value;
|
||||
TInByte _stream;
|
||||
public:
|
||||
bool Create(UInt32 bufSize) { return _stream.Create(bufSize); }
|
||||
void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream);}
|
||||
|
||||
void Init()
|
||||
{
|
||||
_stream.Init();
|
||||
_bitPos = kNumBigValueBits;
|
||||
_value = 0;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
UInt64 GetStreamSize() const { return _stream.GetStreamSize(); }
|
||||
UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); }
|
||||
|
||||
bool ExtraBitsWereRead() const
|
||||
{
|
||||
return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3));
|
||||
}
|
||||
|
||||
bool ExtraBitsWereRead_Fast() const
|
||||
{
|
||||
return (_stream.NumExtraBytes > 4);
|
||||
}
|
||||
|
||||
MY_FORCE_INLINE
|
||||
void Normalize()
|
||||
{
|
||||
for (; _bitPos >= 8; _bitPos -= 8)
|
||||
_value = (_value << 8) | _stream.ReadByte();
|
||||
}
|
||||
|
||||
MY_FORCE_INLINE
|
||||
UInt32 GetValue(unsigned numBits) const
|
||||
{
|
||||
// return (_value << _bitPos) >> (kNumBigValueBits - numBits);
|
||||
return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits);
|
||||
}
|
||||
|
||||
MY_FORCE_INLINE
|
||||
void MovePos(unsigned numBits)
|
||||
{
|
||||
_bitPos += numBits;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
MY_FORCE_INLINE
|
||||
UInt32 ReadBits(unsigned numBits)
|
||||
{
|
||||
UInt32 res = GetValue(numBits);
|
||||
MovePos(numBits);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
unsigned ReadBit()
|
||||
{
|
||||
UInt32 res = ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - 1);
|
||||
if (++_bitPos >= 8)
|
||||
{
|
||||
_value = (_value << 8) | _stream.ReadByte();
|
||||
_bitPos -= 8;
|
||||
}
|
||||
return (unsigned)res;
|
||||
}
|
||||
*/
|
||||
|
||||
void AlignToByte() { MovePos((kNumBigValueBits - _bitPos) & 7); }
|
||||
|
||||
MY_FORCE_INLINE
|
||||
UInt32 ReadAlignBits() { return ReadBits((kNumBigValueBits - _bitPos) & 7); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
// BitmEncoder.h -- the Most Significant Bit of byte is First
|
||||
|
||||
#ifndef __BITM_ENCODER_H
|
||||
#define __BITM_ENCODER_H
|
||||
|
||||
#include "../IStream.h"
|
||||
|
||||
template<class TOutByte>
|
||||
class CBitmEncoder
|
||||
{
|
||||
unsigned _bitPos;
|
||||
Byte _curByte;
|
||||
TOutByte _stream;
|
||||
public:
|
||||
bool Create(UInt32 bufferSize) { return _stream.Create(bufferSize); }
|
||||
void SetStream(ISequentialOutStream *outStream) { _stream.SetStream(outStream);}
|
||||
UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() + ((8 - _bitPos + 7) >> 3); }
|
||||
void Init()
|
||||
{
|
||||
_stream.Init();
|
||||
_bitPos = 8;
|
||||
_curByte = 0;
|
||||
}
|
||||
HRESULT Flush()
|
||||
{
|
||||
if (_bitPos < 8)
|
||||
WriteBits(0, _bitPos);
|
||||
return _stream.Flush();
|
||||
}
|
||||
void WriteBits(UInt32 value, unsigned numBits)
|
||||
{
|
||||
while (numBits > 0)
|
||||
{
|
||||
if (numBits < _bitPos)
|
||||
{
|
||||
_curByte |= ((Byte)value << (_bitPos -= numBits));
|
||||
return;
|
||||
}
|
||||
numBits -= _bitPos;
|
||||
UInt32 newBits = (value >> numBits);
|
||||
value -= (newBits << numBits);
|
||||
_stream.WriteByte((Byte)(_curByte | newBits));
|
||||
_bitPos = 8;
|
||||
_curByte = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
// BranchMisc.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "BranchMisc.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBranch {
|
||||
|
||||
STDMETHODIMP CCoder::Init()
|
||||
{
|
||||
_bufferPos = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(UInt32) CCoder::Filter(Byte *data, UInt32 size)
|
||||
{
|
||||
UInt32 processed = (UInt32)BraFunc(data, size, _bufferPos, _encode);
|
||||
_bufferPos += processed;
|
||||
return processed;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,35 @@
|
||||
// BranchMisc.h
|
||||
|
||||
#ifndef __COMPRESS_BRANCH_MISC_H
|
||||
#define __COMPRESS_BRANCH_MISC_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
typedef SizeT (*Func_Bra)(Byte *data, SizeT size, UInt32 ip, int encoding);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBranch {
|
||||
|
||||
class CCoder:
|
||||
public ICompressFilter,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt32 _bufferPos;
|
||||
int _encode;
|
||||
Func_Bra BraFunc;
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICompressFilter);
|
||||
INTERFACE_ICompressFilter(;)
|
||||
|
||||
CCoder(Func_Bra bra, int encode): _bufferPos(0), _encode(encode), BraFunc(bra) {}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
// BranchRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Bra.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "BranchMisc.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NBranch {
|
||||
|
||||
#define CREATE_BRA(n) \
|
||||
REGISTER_FILTER_CREATE(CreateBra_Decoder_ ## n, CCoder(n ## _Convert, false)) \
|
||||
REGISTER_FILTER_CREATE(CreateBra_Encoder_ ## n, CCoder(n ## _Convert, true)) \
|
||||
|
||||
CREATE_BRA(PPC)
|
||||
CREATE_BRA(IA64)
|
||||
CREATE_BRA(ARM)
|
||||
CREATE_BRA(ARMT)
|
||||
CREATE_BRA(SPARC)
|
||||
|
||||
#define METHOD_ITEM(n, id, name) \
|
||||
REGISTER_FILTER_ITEM( \
|
||||
CreateBra_Decoder_ ## n, \
|
||||
CreateBra_Encoder_ ## n, \
|
||||
0x3030000 + id, name)
|
||||
|
||||
REGISTER_CODECS_VAR
|
||||
{
|
||||
METHOD_ITEM(PPC, 0x205, "PPC"),
|
||||
METHOD_ITEM(IA64, 0x401, "IA64"),
|
||||
METHOD_ITEM(ARM, 0x501, "ARM"),
|
||||
METHOD_ITEM(ARMT, 0x701, "ARMT"),
|
||||
METHOD_ITEM(SPARC, 0x805, "SPARC")
|
||||
};
|
||||
|
||||
REGISTER_CODECS(Branch)
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,92 @@
|
||||
// ByteSwap.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NByteSwap {
|
||||
|
||||
class CByteSwap2:
|
||||
public ICompressFilter,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICompressFilter);
|
||||
INTERFACE_ICompressFilter(;)
|
||||
};
|
||||
|
||||
class CByteSwap4:
|
||||
public ICompressFilter,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICompressFilter);
|
||||
INTERFACE_ICompressFilter(;)
|
||||
};
|
||||
|
||||
STDMETHODIMP CByteSwap2::Init() { return S_OK; }
|
||||
|
||||
STDMETHODIMP_(UInt32) CByteSwap2::Filter(Byte *data, UInt32 size)
|
||||
{
|
||||
const UInt32 kStep = 2;
|
||||
if (size < kStep)
|
||||
return 0;
|
||||
size &= ~(kStep - 1);
|
||||
|
||||
const Byte *end = data + (size_t)size;
|
||||
|
||||
do
|
||||
{
|
||||
Byte b0 = data[0];
|
||||
data[0] = data[1];
|
||||
data[1] = b0;
|
||||
data += kStep;
|
||||
}
|
||||
while (data != end);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
STDMETHODIMP CByteSwap4::Init() { return S_OK; }
|
||||
|
||||
STDMETHODIMP_(UInt32) CByteSwap4::Filter(Byte *data, UInt32 size)
|
||||
{
|
||||
const UInt32 kStep = 4;
|
||||
if (size < kStep)
|
||||
return 0;
|
||||
size &= ~(kStep - 1);
|
||||
|
||||
const Byte *end = data + (size_t)size;
|
||||
|
||||
do
|
||||
{
|
||||
Byte b0 = data[0];
|
||||
Byte b1 = data[1];
|
||||
data[0] = data[3];
|
||||
data[1] = data[2];
|
||||
data[2] = b1;
|
||||
data[3] = b0;
|
||||
data += kStep;
|
||||
}
|
||||
while (data != end);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
REGISTER_FILTER_CREATE(CreateFilter2, CByteSwap2())
|
||||
REGISTER_FILTER_CREATE(CreateFilter4, CByteSwap4())
|
||||
|
||||
REGISTER_CODECS_VAR
|
||||
{
|
||||
REGISTER_FILTER_ITEM(CreateFilter2, CreateFilter2, 0x20302, "Swap2"),
|
||||
REGISTER_FILTER_ITEM(CreateFilter4, CreateFilter4, 0x20304, "Swap4")
|
||||
};
|
||||
|
||||
REGISTER_CODECS(ByteSwap)
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,6 @@
|
||||
EXPORTS
|
||||
CreateObject PRIVATE
|
||||
GetNumberOfMethods PRIVATE
|
||||
GetMethodProperty PRIVATE
|
||||
CreateDecoder PRIVATE
|
||||
CreateEncoder PRIVATE
|
||||
@@ -0,0 +1,344 @@
|
||||
// CodecExports.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/ComTry.h"
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../../Windows/Defs.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
extern unsigned g_NumCodecs;
|
||||
extern const CCodecInfo *g_Codecs[];
|
||||
|
||||
extern unsigned g_NumHashers;
|
||||
extern const CHasherInfo *g_Hashers[];
|
||||
|
||||
static void SetPropFromAscii(const char *s, PROPVARIANT *prop) throw()
|
||||
{
|
||||
UINT len = (UINT)strlen(s);
|
||||
BSTR dest = ::SysAllocStringLen(NULL, len);
|
||||
if (dest)
|
||||
{
|
||||
for (UINT i = 0; i <= len; i++)
|
||||
dest[i] = (Byte)s[i];
|
||||
prop->bstrVal = dest;
|
||||
prop->vt = VT_BSTR;
|
||||
}
|
||||
}
|
||||
|
||||
static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) throw()
|
||||
{
|
||||
if ((value->bstrVal = ::SysAllocStringByteLen((const char *)&guid, sizeof(guid))) != NULL)
|
||||
value->vt = VT_BSTR;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT MethodToClassID(UInt16 typeId, CMethodId id, PROPVARIANT *value) throw()
|
||||
{
|
||||
GUID clsId;
|
||||
clsId.Data1 = k_7zip_GUID_Data1;
|
||||
clsId.Data2 = k_7zip_GUID_Data2;
|
||||
clsId.Data3 = typeId;
|
||||
SetUi64(clsId.Data4, id);
|
||||
return SetPropGUID(clsId, value);
|
||||
}
|
||||
|
||||
static HRESULT FindCodecClassId(const GUID *clsid, bool isCoder2, bool isFilter, bool &encode, int &index) throw()
|
||||
{
|
||||
index = -1;
|
||||
if (clsid->Data1 != k_7zip_GUID_Data1 ||
|
||||
clsid->Data2 != k_7zip_GUID_Data2)
|
||||
return S_OK;
|
||||
|
||||
encode = true;
|
||||
|
||||
if (clsid->Data3 == k_7zip_GUID_Data3_Decoder) encode = false;
|
||||
else if (clsid->Data3 != k_7zip_GUID_Data3_Encoder) return S_OK;
|
||||
|
||||
UInt64 id = GetUi64(clsid->Data4);
|
||||
|
||||
for (unsigned i = 0; i < g_NumCodecs; i++)
|
||||
{
|
||||
const CCodecInfo &codec = *g_Codecs[i];
|
||||
|
||||
if (id != codec.Id
|
||||
|| (encode ? !codec.CreateEncoder : !codec.CreateDecoder)
|
||||
|| (isFilter ? !codec.IsFilter : codec.IsFilter))
|
||||
continue;
|
||||
|
||||
if (codec.NumStreams == 1 ? isCoder2 : !isCoder2)
|
||||
return E_NOINTERFACE;
|
||||
|
||||
index = i;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT CreateCoderMain(unsigned index, bool encode, void **coder)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
|
||||
const CCodecInfo &codec = *g_Codecs[index];
|
||||
|
||||
void *c;
|
||||
if (encode)
|
||||
c = codec.CreateEncoder();
|
||||
else
|
||||
c = codec.CreateDecoder();
|
||||
|
||||
if (c)
|
||||
{
|
||||
IUnknown *unk;
|
||||
if (codec.IsFilter)
|
||||
unk = (IUnknown *)(ICompressFilter *)c;
|
||||
else if (codec.NumStreams != 1)
|
||||
unk = (IUnknown *)(ICompressCoder2 *)c;
|
||||
else
|
||||
unk = (IUnknown *)(ICompressCoder *)c;
|
||||
unk->AddRef();
|
||||
*coder = c;
|
||||
}
|
||||
return S_OK;
|
||||
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
static HRESULT CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject)
|
||||
{
|
||||
*outObject = NULL;
|
||||
|
||||
const CCodecInfo &codec = *g_Codecs[index];
|
||||
|
||||
if (encode ? !codec.CreateEncoder : !codec.CreateDecoder)
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
|
||||
if (codec.IsFilter)
|
||||
{
|
||||
if (*iid != IID_ICompressFilter) return E_NOINTERFACE;
|
||||
}
|
||||
else if (codec.NumStreams != 1)
|
||||
{
|
||||
if (*iid != IID_ICompressCoder2) return E_NOINTERFACE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*iid != IID_ICompressCoder) return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
return CreateCoderMain(index, encode, outObject);
|
||||
}
|
||||
|
||||
STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject)
|
||||
{
|
||||
return CreateCoder2(false, index, iid, outObject);
|
||||
}
|
||||
|
||||
STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject)
|
||||
{
|
||||
return CreateCoder2(true, index, iid, outObject);
|
||||
}
|
||||
|
||||
STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
|
||||
{
|
||||
*outObject = NULL;
|
||||
|
||||
bool isFilter = false;
|
||||
bool isCoder2 = false;
|
||||
bool isCoder = (*iid == IID_ICompressCoder) != 0;
|
||||
if (!isCoder)
|
||||
{
|
||||
isFilter = (*iid == IID_ICompressFilter) != 0;
|
||||
if (!isFilter)
|
||||
{
|
||||
isCoder2 = (*iid == IID_ICompressCoder2) != 0;
|
||||
if (!isCoder2)
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
bool encode;
|
||||
int codecIndex;
|
||||
HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);
|
||||
if (res != S_OK)
|
||||
return res;
|
||||
if (codecIndex < 0)
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
|
||||
return CreateCoderMain(codecIndex, encode, outObject);
|
||||
}
|
||||
|
||||
STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
::VariantClear((VARIANTARG *)value);
|
||||
const CCodecInfo &codec = *g_Codecs[codecIndex];
|
||||
switch (propID)
|
||||
{
|
||||
case NMethodPropID::kID:
|
||||
value->uhVal.QuadPart = (UInt64)codec.Id;
|
||||
value->vt = VT_UI8;
|
||||
break;
|
||||
case NMethodPropID::kName:
|
||||
SetPropFromAscii(codec.Name, value);
|
||||
break;
|
||||
case NMethodPropID::kDecoder:
|
||||
if (codec.CreateDecoder)
|
||||
return MethodToClassID(k_7zip_GUID_Data3_Decoder, codec.Id, value);
|
||||
break;
|
||||
case NMethodPropID::kEncoder:
|
||||
if (codec.CreateEncoder)
|
||||
return MethodToClassID(k_7zip_GUID_Data3_Encoder, codec.Id, value);
|
||||
break;
|
||||
case NMethodPropID::kDecoderIsAssigned:
|
||||
value->vt = VT_BOOL;
|
||||
value->boolVal = BoolToVARIANT_BOOL(codec.CreateDecoder != NULL);
|
||||
break;
|
||||
case NMethodPropID::kEncoderIsAssigned:
|
||||
value->vt = VT_BOOL;
|
||||
value->boolVal = BoolToVARIANT_BOOL(codec.CreateEncoder != NULL);
|
||||
break;
|
||||
case NMethodPropID::kPackStreams:
|
||||
if (codec.NumStreams != 1)
|
||||
{
|
||||
value->vt = VT_UI4;
|
||||
value->ulVal = (ULONG)codec.NumStreams;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
case NMethodPropID::kIsFilter:
|
||||
// if (codec.IsFilter)
|
||||
{
|
||||
value->vt = VT_BOOL;
|
||||
value->boolVal = BoolToVARIANT_BOOL(codec.IsFilter);
|
||||
}
|
||||
break;
|
||||
*/
|
||||
/*
|
||||
case NMethodPropID::kDecoderFlags:
|
||||
{
|
||||
value->vt = VT_UI4;
|
||||
value->ulVal = (ULONG)codec.DecoderFlags;
|
||||
}
|
||||
break;
|
||||
case NMethodPropID::kEncoderFlags:
|
||||
{
|
||||
value->vt = VT_UI4;
|
||||
value->ulVal = (ULONG)codec.EncoderFlags;
|
||||
}
|
||||
break;
|
||||
*/
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDAPI GetNumberOfMethods(UINT32 *numCodecs)
|
||||
{
|
||||
*numCodecs = g_NumCodecs;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// ---------- Hashers ----------
|
||||
|
||||
static int FindHasherClassId(const GUID *clsid) throw()
|
||||
{
|
||||
if (clsid->Data1 != k_7zip_GUID_Data1 ||
|
||||
clsid->Data2 != k_7zip_GUID_Data2 ||
|
||||
clsid->Data3 != k_7zip_GUID_Data3_Hasher)
|
||||
return -1;
|
||||
UInt64 id = GetUi64(clsid->Data4);
|
||||
for (unsigned i = 0; i < g_NumCodecs; i++)
|
||||
if (id == g_Hashers[i]->Id)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static HRESULT CreateHasher2(UInt32 index, IHasher **hasher)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*hasher = g_Hashers[index]->CreateHasher();
|
||||
if (*hasher)
|
||||
(*hasher)->AddRef();
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDAPI CreateHasher(const GUID *clsid, IHasher **outObject)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*outObject = 0;
|
||||
int index = FindHasherClassId(clsid);
|
||||
if (index < 0)
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
return CreateHasher2(index, outObject);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
::VariantClear((VARIANTARG *)value);
|
||||
const CHasherInfo &codec = *g_Hashers[codecIndex];
|
||||
switch (propID)
|
||||
{
|
||||
case NMethodPropID::kID:
|
||||
value->uhVal.QuadPart = (UInt64)codec.Id;
|
||||
value->vt = VT_UI8;
|
||||
break;
|
||||
case NMethodPropID::kName:
|
||||
SetPropFromAscii(codec.Name, value);
|
||||
break;
|
||||
case NMethodPropID::kEncoder:
|
||||
if (codec.CreateHasher)
|
||||
return MethodToClassID(k_7zip_GUID_Data3_Hasher, codec.Id, value);
|
||||
break;
|
||||
case NMethodPropID::kDigestSize:
|
||||
value->ulVal = (ULONG)codec.DigestSize;
|
||||
value->vt = VT_UI4;
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class CHashers:
|
||||
public IHashers,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IHashers)
|
||||
|
||||
STDMETHOD_(UInt32, GetNumHashers)();
|
||||
STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);
|
||||
STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);
|
||||
};
|
||||
|
||||
STDAPI GetHashers(IHashers **hashers)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
*hashers = new CHashers;
|
||||
if (*hashers)
|
||||
(*hashers)->AddRef();
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP_(UInt32) CHashers::GetNumHashers()
|
||||
{
|
||||
return g_NumHashers;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
return ::GetHasherProp(index, propID, value);
|
||||
}
|
||||
|
||||
STDMETHODIMP CHashers::CreateHasher(UInt32 index, IHasher **hasher)
|
||||
{
|
||||
return ::CreateHasher2(index, hasher);
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
// Compress/CopyCoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "CopyCoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
|
||||
static const UInt32 kBufSize = 1 << 17;
|
||||
|
||||
CCopyCoder::~CCopyCoder()
|
||||
{
|
||||
::MidFree(_buf);
|
||||
}
|
||||
|
||||
STDMETHODIMP CCopyCoder::SetFinishMode(UInt32 /* finishMode */)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream,
|
||||
ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize,
|
||||
ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_buf)
|
||||
{
|
||||
_buf = (Byte *)::MidAlloc(kBufSize);
|
||||
if (!_buf)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
TotalSize = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
UInt32 size = kBufSize;
|
||||
if (outSize && size > *outSize - TotalSize)
|
||||
size = (UInt32)(*outSize - TotalSize);
|
||||
if (size == 0)
|
||||
return S_OK;
|
||||
|
||||
HRESULT readRes = inStream->Read(_buf, size, &size);
|
||||
|
||||
if (size == 0)
|
||||
return readRes;
|
||||
|
||||
if (outStream)
|
||||
{
|
||||
UInt32 pos = 0;
|
||||
do
|
||||
{
|
||||
UInt32 curSize = size - pos;
|
||||
HRESULT res = outStream->Write(_buf + pos, curSize, &curSize);
|
||||
pos += curSize;
|
||||
TotalSize += curSize;
|
||||
RINOK(res);
|
||||
if (curSize == 0)
|
||||
return E_FAIL;
|
||||
}
|
||||
while (pos < size);
|
||||
}
|
||||
else
|
||||
TotalSize += size;
|
||||
|
||||
RINOK(readRes);
|
||||
|
||||
if (progress)
|
||||
{
|
||||
RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP CCopyCoder::SetInStream(ISequentialInStream *inStream)
|
||||
{
|
||||
_inStream = inStream;
|
||||
TotalSize = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CCopyCoder::ReleaseInStream()
|
||||
{
|
||||
_inStream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize = 0;
|
||||
HRESULT res = _inStream->Read(data, size, &realProcessedSize);
|
||||
TotalSize += realProcessedSize;
|
||||
if (processedSize)
|
||||
*processedSize = realProcessedSize;
|
||||
return res;
|
||||
}
|
||||
|
||||
STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
*value = TotalSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
|
||||
{
|
||||
CMyComPtr<ICompressCoder> copyCoder = new CCopyCoder;
|
||||
return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
|
||||
}
|
||||
|
||||
HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress)
|
||||
{
|
||||
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
|
||||
CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
|
||||
RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress));
|
||||
return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// Compress/CopyCoder.h
|
||||
|
||||
#ifndef __COMPRESS_COPY_CODER_H
|
||||
#define __COMPRESS_COPY_CODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
|
||||
class CCopyCoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetInStream,
|
||||
public ISequentialInStream,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
Byte *_buf;
|
||||
CMyComPtr<ISequentialInStream> _inStream;
|
||||
public:
|
||||
UInt64 TotalSize;
|
||||
|
||||
CCopyCoder(): _buf(0), TotalSize(0) {};
|
||||
~CCopyCoder();
|
||||
|
||||
MY_UNKNOWN_IMP5(
|
||||
ICompressCoder,
|
||||
ICompressSetInStream,
|
||||
ISequentialInStream,
|
||||
ICompressSetFinishMode,
|
||||
ICompressGetInStreamProcessedSize)
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
|
||||
STDMETHOD(ReleaseInStream)();
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
};
|
||||
|
||||
HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
|
||||
HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
// CopyRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "CopyCoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
|
||||
REGISTER_CODEC_CREATE(CreateCodec, CCopyCoder())
|
||||
|
||||
REGISTER_CODEC_2(Copy, CreateCodec, CreateCodec, 0, "Copy")
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Deflate64Register.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "DeflateDecoder.h"
|
||||
|
||||
#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY)
|
||||
#include "DeflateEncoder.h"
|
||||
#endif
|
||||
|
||||
namespace NCompress {
|
||||
namespace NDeflate {
|
||||
|
||||
REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder64())
|
||||
|
||||
#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY)
|
||||
REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder64())
|
||||
#else
|
||||
#define CreateEnc NULL
|
||||
#endif
|
||||
|
||||
REGISTER_CODEC_2(Deflate64, CreateDec, CreateEnc, 0x40109, "Deflate64")
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,131 @@
|
||||
// DeflateConst.h
|
||||
|
||||
#ifndef __DEFLATE_CONST_H
|
||||
#define __DEFLATE_CONST_H
|
||||
|
||||
namespace NCompress {
|
||||
namespace NDeflate {
|
||||
|
||||
const unsigned kNumHuffmanBits = 15;
|
||||
|
||||
const UInt32 kHistorySize32 = (1 << 15);
|
||||
const UInt32 kHistorySize64 = (1 << 16);
|
||||
|
||||
const unsigned kDistTableSize32 = 30;
|
||||
const unsigned kDistTableSize64 = 32;
|
||||
|
||||
const unsigned kNumLenSymbols32 = 256;
|
||||
const unsigned kNumLenSymbols64 = 255; // don't change it. It must be <= 255.
|
||||
const unsigned kNumLenSymbolsMax = kNumLenSymbols32;
|
||||
|
||||
const unsigned kNumLenSlots = 29;
|
||||
|
||||
const unsigned kFixedDistTableSize = 32;
|
||||
const unsigned kFixedLenTableSize = 31;
|
||||
|
||||
const unsigned kSymbolEndOfBlock = 0x100;
|
||||
const unsigned kSymbolMatch = kSymbolEndOfBlock + 1;
|
||||
|
||||
const unsigned kMainTableSize = kSymbolMatch + kNumLenSlots;
|
||||
const unsigned kFixedMainTableSize = kSymbolMatch + kFixedLenTableSize;
|
||||
|
||||
const unsigned kLevelTableSize = 19;
|
||||
|
||||
const unsigned kTableDirectLevels = 16;
|
||||
const unsigned kTableLevelRepNumber = kTableDirectLevels;
|
||||
const unsigned kTableLevel0Number = kTableLevelRepNumber + 1;
|
||||
const unsigned kTableLevel0Number2 = kTableLevel0Number + 1;
|
||||
|
||||
const unsigned kLevelMask = 0xF;
|
||||
|
||||
const Byte kLenStart32[kFixedLenTableSize] =
|
||||
{0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224, 255, 0, 0};
|
||||
const Byte kLenStart64[kFixedLenTableSize] =
|
||||
{0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224, 0, 0, 0};
|
||||
|
||||
const Byte kLenDirectBits32[kFixedLenTableSize] =
|
||||
{0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0};
|
||||
const Byte kLenDirectBits64[kFixedLenTableSize] =
|
||||
{0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 16, 0, 0};
|
||||
|
||||
const UInt32 kDistStart[kDistTableSize64] =
|
||||
{0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,
|
||||
1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768,49152};
|
||||
const Byte kDistDirectBits[kDistTableSize64] =
|
||||
{0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14};
|
||||
|
||||
const Byte kLevelDirectBits[3] = {2, 3, 7};
|
||||
|
||||
const Byte kCodeLengthAlphabetOrder[kLevelTableSize] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
|
||||
|
||||
const unsigned kMatchMinLen = 3;
|
||||
const unsigned kMatchMaxLen32 = kNumLenSymbols32 + kMatchMinLen - 1; // 256 + 2
|
||||
const unsigned kMatchMaxLen64 = kNumLenSymbols64 + kMatchMinLen - 1; // 255 + 2
|
||||
const unsigned kMatchMaxLen = kMatchMaxLen32;
|
||||
|
||||
const unsigned kFinalBlockFieldSize = 1;
|
||||
|
||||
namespace NFinalBlockField
|
||||
{
|
||||
enum
|
||||
{
|
||||
kNotFinalBlock = 0,
|
||||
kFinalBlock = 1
|
||||
};
|
||||
}
|
||||
|
||||
const unsigned kBlockTypeFieldSize = 2;
|
||||
|
||||
namespace NBlockType
|
||||
{
|
||||
enum
|
||||
{
|
||||
kStored = 0,
|
||||
kFixedHuffman = 1,
|
||||
kDynamicHuffman = 2
|
||||
};
|
||||
}
|
||||
|
||||
const unsigned kNumLenCodesFieldSize = 5;
|
||||
const unsigned kNumDistCodesFieldSize = 5;
|
||||
const unsigned kNumLevelCodesFieldSize = 4;
|
||||
|
||||
const unsigned kNumLitLenCodesMin = 257;
|
||||
const unsigned kNumDistCodesMin = 1;
|
||||
const unsigned kNumLevelCodesMin = 4;
|
||||
|
||||
const unsigned kLevelFieldSize = 3;
|
||||
|
||||
const unsigned kStoredBlockLengthFieldSize = 16;
|
||||
|
||||
struct CLevels
|
||||
{
|
||||
Byte litLenLevels[kFixedMainTableSize];
|
||||
Byte distLevels[kFixedDistTableSize];
|
||||
|
||||
void SubClear()
|
||||
{
|
||||
unsigned i;
|
||||
for (i = kNumLitLenCodesMin; i < kFixedMainTableSize; i++)
|
||||
litLenLevels[i] = 0;
|
||||
for (i = 0; i < kFixedDistTableSize; i++)
|
||||
distLevels[i] = 0;
|
||||
}
|
||||
|
||||
void SetFixedLevels()
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
for (; i < 144; i++) litLenLevels[i] = 8;
|
||||
for (; i < 256; i++) litLenLevels[i] = 9;
|
||||
for (; i < 280; i++) litLenLevels[i] = 7;
|
||||
for (; i < 288; i++) litLenLevels[i] = 8;
|
||||
|
||||
for (i = 0; i < kFixedDistTableSize; i++) // test it: InfoZip only uses kDistTableSize
|
||||
distLevels[i] = 5;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,517 @@
|
||||
// DeflateDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "DeflateDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NDeflate {
|
||||
namespace NDecoder {
|
||||
|
||||
CCoder::CCoder(bool deflate64Mode):
|
||||
_deflate64Mode(deflate64Mode),
|
||||
_deflateNSIS(false),
|
||||
_keepHistory(false),
|
||||
_needFinishInput(false),
|
||||
_needInitInStream(true),
|
||||
_outSizeDefined(false),
|
||||
_outStartPos(0),
|
||||
ZlibMode(false) {}
|
||||
|
||||
UInt32 CCoder::ReadBits(unsigned numBits)
|
||||
{
|
||||
return m_InBitStream.ReadBits(numBits);
|
||||
}
|
||||
|
||||
Byte CCoder::ReadAlignedByte()
|
||||
{
|
||||
return m_InBitStream.ReadAlignedByte();
|
||||
}
|
||||
|
||||
bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols)
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
|
||||
if (sym < kTableDirectLevels)
|
||||
levels[i++] = (Byte)sym;
|
||||
else
|
||||
{
|
||||
if (sym >= kLevelTableSize)
|
||||
return false;
|
||||
|
||||
unsigned num;
|
||||
unsigned numBits;
|
||||
Byte symbol;
|
||||
|
||||
if (sym == kTableLevelRepNumber)
|
||||
{
|
||||
if (i == 0)
|
||||
return false;
|
||||
numBits = 2;
|
||||
num = 0;
|
||||
symbol = levels[(size_t)i - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
while (i < numSymbols);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define RIF(x) { if (!(x)) return false; }
|
||||
|
||||
bool CCoder::ReadTables(void)
|
||||
{
|
||||
m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
UInt32 blockType = ReadBits(kBlockTypeFieldSize);
|
||||
if (blockType > NBlockType::kDynamicHuffman)
|
||||
return false;
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
|
||||
if (blockType == NBlockType::kStored)
|
||||
{
|
||||
m_StoredMode = true;
|
||||
m_InBitStream.AlignToByte();
|
||||
m_StoredBlockSize = ReadAligned_UInt16(); // ReadBits(kStoredBlockLengthFieldSize)
|
||||
if (_deflateNSIS)
|
||||
return true;
|
||||
return (m_StoredBlockSize == (UInt16)~ReadAligned_UInt16());
|
||||
}
|
||||
|
||||
m_StoredMode = false;
|
||||
|
||||
CLevels levels;
|
||||
if (blockType == NBlockType::kFixedHuffman)
|
||||
{
|
||||
levels.SetFixedLevels();
|
||||
_numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;
|
||||
_numDistLevels = ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;
|
||||
unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;
|
||||
|
||||
if (!_deflate64Mode)
|
||||
if (_numDistLevels > kDistTableSize32)
|
||||
return false;
|
||||
|
||||
Byte levelLevels[kLevelTableSize];
|
||||
for (unsigned i = 0; i < kLevelTableSize; i++)
|
||||
{
|
||||
unsigned position = kCodeLengthAlphabetOrder[i];
|
||||
if (i < numLevelCodes)
|
||||
levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);
|
||||
else
|
||||
levelLevels[position] = 0;
|
||||
}
|
||||
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
|
||||
RIF(m_LevelDecoder.Build(levelLevels));
|
||||
|
||||
Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
|
||||
if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels))
|
||||
return false;
|
||||
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
|
||||
levels.SubClear();
|
||||
memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
|
||||
memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
|
||||
}
|
||||
RIF(m_MainDecoder.Build(levels.litLenLevels));
|
||||
return m_DistDecoder.Build(levels.distLevels);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CCoder::InitInStream(bool needInit)
|
||||
{
|
||||
if (needInit)
|
||||
{
|
||||
// for HDD-Windows:
|
||||
// (1 << 15) - best for reading only prefetch
|
||||
// (1 << 22) - best for real reading / writing
|
||||
if (!m_InBitStream.Create(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
m_InBitStream.Init();
|
||||
_needInitInStream = false;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit)
|
||||
{
|
||||
if (_remainLen == kLenIdFinished)
|
||||
return S_OK;
|
||||
|
||||
if (_remainLen == kLenIdNeedInit)
|
||||
{
|
||||
if (!_keepHistory)
|
||||
if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
|
||||
return E_OUTOFMEMORY;
|
||||
RINOK(InitInStream(_needInitInStream));
|
||||
m_OutWindowStream.Init(_keepHistory);
|
||||
|
||||
m_FinalBlock = false;
|
||||
_remainLen = 0;
|
||||
_needReadTable = true;
|
||||
}
|
||||
|
||||
while (_remainLen > 0 && curSize > 0)
|
||||
{
|
||||
_remainLen--;
|
||||
Byte b = m_OutWindowStream.GetByte(_rep0);
|
||||
m_OutWindowStream.PutByte(b);
|
||||
curSize--;
|
||||
}
|
||||
|
||||
UInt64 inputStart = 0;
|
||||
if (inputProgressLimit != 0)
|
||||
inputStart = m_InBitStream.GetProcessedSize();
|
||||
|
||||
while (curSize > 0 || finishInputStream)
|
||||
{
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return S_FALSE;
|
||||
|
||||
if (_needReadTable)
|
||||
{
|
||||
if (m_FinalBlock)
|
||||
{
|
||||
_remainLen = kLenIdFinished;
|
||||
break;
|
||||
}
|
||||
|
||||
if (inputProgressLimit != 0)
|
||||
if (m_InBitStream.GetProcessedSize() - inputStart >= inputProgressLimit)
|
||||
return S_OK;
|
||||
|
||||
if (!ReadTables())
|
||||
return S_FALSE;
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return S_FALSE;
|
||||
_needReadTable = false;
|
||||
}
|
||||
|
||||
if (m_StoredMode)
|
||||
{
|
||||
if (finishInputStream && curSize == 0 && m_StoredBlockSize != 0)
|
||||
return S_FALSE;
|
||||
/* NSIS version contains some bits in bitl bits buffer.
|
||||
So we must read some first bytes via ReadAlignedByte */
|
||||
for (; m_StoredBlockSize > 0 && curSize > 0 && m_InBitStream.ThereAreDataInBitsBuffer(); m_StoredBlockSize--, curSize--)
|
||||
m_OutWindowStream.PutByte(ReadAlignedByte());
|
||||
for (; m_StoredBlockSize > 0 && curSize > 0; m_StoredBlockSize--, curSize--)
|
||||
m_OutWindowStream.PutByte(m_InBitStream.ReadDirectByte());
|
||||
_needReadTable = (m_StoredBlockSize == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
while (curSize > 0)
|
||||
{
|
||||
if (m_InBitStream.ExtraBitsWereRead_Fast())
|
||||
return S_FALSE;
|
||||
|
||||
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
|
||||
|
||||
if (sym < 0x100)
|
||||
{
|
||||
m_OutWindowStream.PutByte((Byte)sym);
|
||||
curSize--;
|
||||
continue;
|
||||
}
|
||||
else if (sym == kSymbolEndOfBlock)
|
||||
{
|
||||
_needReadTable = true;
|
||||
break;
|
||||
}
|
||||
else if (sym < kMainTableSize)
|
||||
{
|
||||
sym -= kSymbolMatch;
|
||||
UInt32 len;
|
||||
{
|
||||
unsigned numBits;
|
||||
if (_deflate64Mode)
|
||||
{
|
||||
len = kLenStart64[sym];
|
||||
numBits = kLenDirectBits64[sym];
|
||||
}
|
||||
else
|
||||
{
|
||||
len = kLenStart32[sym];
|
||||
numBits = kLenDirectBits32[sym];
|
||||
}
|
||||
len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
|
||||
}
|
||||
UInt32 locLen = len;
|
||||
if (locLen > curSize)
|
||||
locLen = (UInt32)curSize;
|
||||
sym = m_DistDecoder.Decode(&m_InBitStream);
|
||||
if (sym >= _numDistLevels)
|
||||
return S_FALSE;
|
||||
UInt32 distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
|
||||
if (!m_OutWindowStream.CopyBlock(distance, locLen))
|
||||
return S_FALSE;
|
||||
curSize -= locLen;
|
||||
len -= locLen;
|
||||
if (len != 0)
|
||||
{
|
||||
_remainLen = (Int32)len;
|
||||
_rep0 = distance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (finishInputStream && curSize == 0)
|
||||
{
|
||||
if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock)
|
||||
return S_FALSE;
|
||||
_needReadTable = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return S_FALSE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _NO_EXCEPTIONS
|
||||
|
||||
#define DEFLATE_TRY_BEGIN
|
||||
#define DEFLATE_TRY_END(res)
|
||||
|
||||
#else
|
||||
|
||||
#define DEFLATE_TRY_BEGIN try {
|
||||
#define DEFLATE_TRY_END(res) } \
|
||||
catch(const CSystemException &e) { res = e.ErrorCode; } \
|
||||
catch(...) { res = S_FALSE; }
|
||||
|
||||
// catch(const CInBufferException &e) { res = e.ErrorCode; }
|
||||
// catch(const CLzOutWindowException &e) { res = e.ErrorCode; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress)
|
||||
{
|
||||
HRESULT res;
|
||||
|
||||
DEFLATE_TRY_BEGIN
|
||||
|
||||
m_OutWindowStream.SetStream(outStream);
|
||||
CCoderReleaser flusher(this);
|
||||
|
||||
const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const UInt32 kInputProgressLimit = 1 << 21;
|
||||
UInt32 curSize = 1 << 20;
|
||||
bool finishInputStream = false;
|
||||
if (_outSizeDefined)
|
||||
{
|
||||
const UInt64 rem = _outSize - GetOutProcessedCur();
|
||||
if (curSize >= rem)
|
||||
{
|
||||
curSize = (UInt32)rem;
|
||||
if (ZlibMode || _needFinishInput)
|
||||
finishInputStream = true;
|
||||
}
|
||||
}
|
||||
if (!finishInputStream && curSize == 0)
|
||||
break;
|
||||
|
||||
RINOK(CodeSpec(curSize, finishInputStream, progress ? kInputProgressLimit : 0));
|
||||
|
||||
if (_remainLen == kLenIdFinished)
|
||||
break;
|
||||
|
||||
if (progress)
|
||||
{
|
||||
const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;
|
||||
const UInt64 nowPos64 = GetOutProcessedCur();
|
||||
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())
|
||||
return S_FALSE;
|
||||
|
||||
DEFLATE_TRY_END(res)
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
SetInStream(inStream);
|
||||
SetOutStreamSize(outSize);
|
||||
HRESULT res = CodeReal(outStream, progress);
|
||||
ReleaseInStream();
|
||||
/*
|
||||
if (res == S_OK)
|
||||
if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize())
|
||||
res = S_FALSE;
|
||||
*/
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::SetFinishMode(UInt32 finishMode)
|
||||
{
|
||||
Set_NeedFinishInput(finishMode != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
if (!value)
|
||||
return E_INVALIDARG;
|
||||
*value = m_InBitStream.GetProcessedSize();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream)
|
||||
{
|
||||
m_InStreamRef = inStream;
|
||||
m_InBitStream.SetStream(inStream);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::ReleaseInStream()
|
||||
{
|
||||
m_InStreamRef.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void CCoder::SetOutStreamSizeResume(const UInt64 *outSize)
|
||||
{
|
||||
_outSizeDefined = (outSize != NULL);
|
||||
_outSize = 0;
|
||||
if (_outSizeDefined)
|
||||
_outSize = *outSize;
|
||||
|
||||
m_OutWindowStream.Init(_keepHistory);
|
||||
_outStartPos = m_OutWindowStream.GetProcessedSize();
|
||||
|
||||
_remainLen = kLenIdNeedInit;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::SetOutStreamSize(const UInt64 *outSize)
|
||||
{
|
||||
/*
|
||||
18.06:
|
||||
We want to support GetInputProcessedSize() before CCoder::Read()
|
||||
So we call m_InBitStream.Init() even before buffer allocations
|
||||
m_InBitStream.Init() just sets variables to default values
|
||||
But later we will call m_InBitStream.Init() again with real buffer pointers
|
||||
*/
|
||||
m_InBitStream.Init();
|
||||
_needInitInStream = true;
|
||||
SetOutStreamSizeResume(outSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
|
||||
STDMETHODIMP CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
HRESULT res;
|
||||
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
const UInt64 outPos = GetOutProcessedCur();
|
||||
|
||||
bool finishInputStream = false;
|
||||
if (_outSizeDefined)
|
||||
{
|
||||
const UInt64 rem = _outSize - outPos;
|
||||
if (size >= rem)
|
||||
{
|
||||
size = (UInt32)rem;
|
||||
if (ZlibMode || _needFinishInput)
|
||||
finishInputStream = true;
|
||||
}
|
||||
}
|
||||
if (!finishInputStream && size == 0)
|
||||
return S_OK;
|
||||
|
||||
DEFLATE_TRY_BEGIN
|
||||
|
||||
m_OutWindowStream.SetMemStream((Byte *)data);
|
||||
|
||||
res = CodeSpec(size, finishInputStream);
|
||||
|
||||
DEFLATE_TRY_END(res)
|
||||
|
||||
{
|
||||
HRESULT res2 = Flush();
|
||||
if (res2 != S_OK)
|
||||
res = res2;
|
||||
}
|
||||
|
||||
if (processedSize)
|
||||
*processedSize = (UInt32)(GetOutProcessedCur() - outPos);
|
||||
|
||||
m_OutWindowStream.SetMemStream(NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
HRESULT CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
SetOutStreamSizeResume(outSize);
|
||||
return CodeReal(outStream, progress);
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -0,0 +1,153 @@
|
||||
// DeflateDecoder.h
|
||||
|
||||
#ifndef __DEFLATE_DECODER_H
|
||||
#define __DEFLATE_DECODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
|
||||
#include "BitlDecoder.h"
|
||||
#include "DeflateConst.h"
|
||||
#include "HuffmanDecoder.h"
|
||||
#include "LzOutWindow.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NDeflate {
|
||||
namespace NDecoder {
|
||||
|
||||
const int kLenIdFinished = -1;
|
||||
const int kLenIdNeedInit = -2;
|
||||
|
||||
class CCoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
public ICompressSetInStream,
|
||||
public ICompressSetOutStreamSize,
|
||||
public ISequentialInStream,
|
||||
#endif
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzOutWindow m_OutWindowStream;
|
||||
CMyComPtr<ISequentialInStream> m_InStreamRef;
|
||||
NBitl::CDecoder<CInBuffer> m_InBitStream;
|
||||
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedMainTableSize> m_MainDecoder;
|
||||
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedDistTableSize> m_DistDecoder;
|
||||
NCompress::NHuffman::CDecoder7b<kLevelTableSize> m_LevelDecoder;
|
||||
|
||||
UInt32 m_StoredBlockSize;
|
||||
|
||||
UInt32 _numDistLevels;
|
||||
bool m_FinalBlock;
|
||||
bool m_StoredMode;
|
||||
|
||||
bool _deflateNSIS;
|
||||
bool _deflate64Mode;
|
||||
bool _keepHistory;
|
||||
bool _needFinishInput;
|
||||
|
||||
bool _needInitInStream;
|
||||
bool _needReadTable;
|
||||
Int32 _remainLen;
|
||||
UInt32 _rep0;
|
||||
|
||||
bool _outSizeDefined;
|
||||
UInt64 _outSize;
|
||||
UInt64 _outStartPos;
|
||||
|
||||
void SetOutStreamSizeResume(const UInt64 *outSize);
|
||||
UInt64 GetOutProcessedCur() const { return m_OutWindowStream.GetProcessedSize() - _outStartPos; }
|
||||
|
||||
UInt32 ReadBits(unsigned numBits);
|
||||
|
||||
bool DecodeLevels(Byte *levels, unsigned numSymbols);
|
||||
bool ReadTables();
|
||||
|
||||
HRESULT Flush() { return m_OutWindowStream.Flush(); }
|
||||
class CCoderReleaser
|
||||
{
|
||||
CCoder *_coder;
|
||||
public:
|
||||
bool NeedFlush;
|
||||
CCoderReleaser(CCoder *coder): _coder(coder), NeedFlush(true) {}
|
||||
~CCoderReleaser()
|
||||
{
|
||||
if (NeedFlush)
|
||||
_coder->Flush();
|
||||
}
|
||||
};
|
||||
friend class CCoderReleaser;
|
||||
|
||||
HRESULT CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit = 0);
|
||||
public:
|
||||
bool ZlibMode;
|
||||
Byte ZlibFooter[4];
|
||||
|
||||
CCoder(bool deflate64Mode);
|
||||
virtual ~CCoder() {};
|
||||
|
||||
void SetNsisMode(bool nsisMode) { _deflateNSIS = nsisMode; }
|
||||
|
||||
void Set_KeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
|
||||
void Set_NeedFinishInput(bool needFinishInput) { _needFinishInput = needFinishInput; }
|
||||
|
||||
bool IsFinished() const { return _remainLen == kLenIdFinished;; }
|
||||
bool IsFinalBlock() const { return m_FinalBlock; }
|
||||
|
||||
HRESULT CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress);
|
||||
|
||||
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
|
||||
MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
|
||||
#endif
|
||||
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
|
||||
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
|
||||
STDMETHOD(ReleaseInStream)();
|
||||
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
#endif
|
||||
|
||||
HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
HRESULT InitInStream(bool needInit);
|
||||
|
||||
void AlignToByte() { m_InBitStream.AlignToByte(); }
|
||||
Byte ReadAlignedByte();
|
||||
UInt32 ReadAligned_UInt16() // aligned for Byte range
|
||||
{
|
||||
UInt32 v = m_InBitStream.ReadAlignedByte();
|
||||
return v | ((UInt32)m_InBitStream.ReadAlignedByte() << 8);
|
||||
}
|
||||
bool InputEofError() const { return m_InBitStream.ExtraBitsWereRead(); }
|
||||
|
||||
UInt64 GetStreamSize() const { return m_InBitStream.GetStreamSize(); }
|
||||
UInt64 GetInputProcessedSize() const { return m_InBitStream.GetProcessedSize(); }
|
||||
};
|
||||
|
||||
class CCOMCoder : public CCoder { public: CCOMCoder(): CCoder(false) {} };
|
||||
class CCOMCoder64 : public CCoder { public: CCOMCoder64(): CCoder(true) {} };
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,209 @@
|
||||
// DeflateEncoder.h
|
||||
|
||||
#ifndef __DEFLATE_ENCODER_H
|
||||
#define __DEFLATE_ENCODER_H
|
||||
|
||||
#include "../../../C/LzFind.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "BitlEncoder.h"
|
||||
#include "DeflateConst.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NDeflate {
|
||||
namespace NEncoder {
|
||||
|
||||
struct CCodeValue
|
||||
{
|
||||
UInt16 Len;
|
||||
UInt16 Pos;
|
||||
void SetAsLiteral() { Len = (1 << 15); }
|
||||
bool IsLiteral() const { return (Len >= (1 << 15)); }
|
||||
};
|
||||
|
||||
struct COptimal
|
||||
{
|
||||
UInt32 Price;
|
||||
UInt16 PosPrev;
|
||||
UInt16 BackPrev;
|
||||
};
|
||||
|
||||
const UInt32 kNumOptsBase = 1 << 12;
|
||||
const UInt32 kNumOpts = kNumOptsBase + kMatchMaxLen;
|
||||
|
||||
class CCoder;
|
||||
|
||||
struct CTables: public CLevels
|
||||
{
|
||||
bool UseSubBlocks;
|
||||
bool StoreMode;
|
||||
bool StaticMode;
|
||||
UInt32 BlockSizeRes;
|
||||
UInt32 m_Pos;
|
||||
void InitStructures();
|
||||
};
|
||||
|
||||
|
||||
struct CEncProps
|
||||
{
|
||||
int Level;
|
||||
int algo;
|
||||
int fb;
|
||||
int btMode;
|
||||
UInt32 mc;
|
||||
UInt32 numPasses;
|
||||
|
||||
CEncProps()
|
||||
{
|
||||
Level = -1;
|
||||
mc = 0;
|
||||
algo = fb = btMode = -1;
|
||||
numPasses = (UInt32)(Int32)-1;
|
||||
}
|
||||
void Normalize();
|
||||
};
|
||||
|
||||
class CCoder
|
||||
{
|
||||
CMatchFinder _lzInWindow;
|
||||
CBitlEncoder m_OutStream;
|
||||
|
||||
public:
|
||||
CCodeValue *m_Values;
|
||||
|
||||
UInt16 *m_MatchDistances;
|
||||
UInt32 m_NumFastBytes;
|
||||
bool _fastMode;
|
||||
bool _btMode;
|
||||
|
||||
UInt16 *m_OnePosMatchesMemory;
|
||||
UInt16 *m_DistanceMemory;
|
||||
|
||||
UInt32 m_Pos;
|
||||
|
||||
unsigned m_NumPasses;
|
||||
unsigned m_NumDivPasses;
|
||||
bool m_CheckStatic;
|
||||
bool m_IsMultiPass;
|
||||
UInt32 m_ValueBlockSize;
|
||||
|
||||
UInt32 m_NumLenCombinations;
|
||||
UInt32 m_MatchMaxLen;
|
||||
const Byte *m_LenStart;
|
||||
const Byte *m_LenDirectBits;
|
||||
|
||||
bool m_Created;
|
||||
bool m_Deflate64Mode;
|
||||
|
||||
Byte m_LevelLevels[kLevelTableSize];
|
||||
unsigned m_NumLitLenLevels;
|
||||
unsigned m_NumDistLevels;
|
||||
UInt32 m_NumLevelCodes;
|
||||
UInt32 m_ValueIndex;
|
||||
|
||||
bool m_SecondPass;
|
||||
UInt32 m_AdditionalOffset;
|
||||
|
||||
UInt32 m_OptimumEndIndex;
|
||||
UInt32 m_OptimumCurrentIndex;
|
||||
|
||||
Byte m_LiteralPrices[256];
|
||||
Byte m_LenPrices[kNumLenSymbolsMax];
|
||||
Byte m_PosPrices[kDistTableSize64];
|
||||
|
||||
CLevels m_NewLevels;
|
||||
UInt32 mainFreqs[kFixedMainTableSize];
|
||||
UInt32 distFreqs[kDistTableSize64];
|
||||
UInt32 mainCodes[kFixedMainTableSize];
|
||||
UInt32 distCodes[kDistTableSize64];
|
||||
UInt32 levelCodes[kLevelTableSize];
|
||||
Byte levelLens[kLevelTableSize];
|
||||
|
||||
UInt32 BlockSizeRes;
|
||||
|
||||
CTables *m_Tables;
|
||||
COptimal m_Optimum[kNumOpts];
|
||||
|
||||
UInt32 m_MatchFinderCycles;
|
||||
|
||||
void GetMatches();
|
||||
void MovePos(UInt32 num);
|
||||
UInt32 Backward(UInt32 &backRes, UInt32 cur);
|
||||
UInt32 GetOptimal(UInt32 &backRes);
|
||||
UInt32 GetOptimalFast(UInt32 &backRes);
|
||||
|
||||
void LevelTableDummy(const Byte *levels, unsigned numLevels, UInt32 *freqs);
|
||||
|
||||
void WriteBits(UInt32 value, unsigned numBits);
|
||||
void LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes);
|
||||
|
||||
void MakeTables(unsigned maxHuffLen);
|
||||
UInt32 GetLzBlockPrice() const;
|
||||
void TryBlock();
|
||||
UInt32 TryDynBlock(unsigned tableIndex, UInt32 numPasses);
|
||||
|
||||
UInt32 TryFixedBlock(unsigned tableIndex);
|
||||
|
||||
void SetPrices(const CLevels &levels);
|
||||
void WriteBlock();
|
||||
|
||||
HRESULT Create();
|
||||
void Free();
|
||||
|
||||
void WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock);
|
||||
void WriteTables(bool writeMode, bool finalBlock);
|
||||
|
||||
void WriteBlockData(bool writeMode, bool finalBlock);
|
||||
|
||||
UInt32 GetBlockPrice(unsigned tableIndex, unsigned numDivPasses);
|
||||
void CodeBlock(unsigned tableIndex, bool finalBlock);
|
||||
|
||||
void SetProps(const CEncProps *props2);
|
||||
public:
|
||||
CCoder(bool deflate64Mode = false);
|
||||
~CCoder();
|
||||
|
||||
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
HRESULT BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
HRESULT BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
};
|
||||
|
||||
|
||||
class CCOMCoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
public CMyUnknownImp,
|
||||
public CCoder
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(ICompressCoder, ICompressSetCoderProperties)
|
||||
CCOMCoder(): CCoder(false) {};
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
};
|
||||
|
||||
class CCOMCoder64 :
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
public CMyUnknownImp,
|
||||
public CCoder
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(ICompressCoder, ICompressSetCoderProperties)
|
||||
CCOMCoder64(): CCoder(true) {};
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
// DeflateRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "DeflateDecoder.h"
|
||||
#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY)
|
||||
#include "DeflateEncoder.h"
|
||||
#endif
|
||||
|
||||
namespace NCompress {
|
||||
namespace NDeflate {
|
||||
|
||||
REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder)
|
||||
|
||||
#if !defined(EXTRACT_ONLY) && !defined(DEFLATE_EXTRACT_ONLY)
|
||||
REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder)
|
||||
#else
|
||||
#define CreateEnc NULL
|
||||
#endif
|
||||
|
||||
REGISTER_CODEC_2(Deflate, CreateDec, CreateEnc, 0x40108, "Deflate")
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,128 @@
|
||||
// DeltaFilter.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Delta.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NDelta {
|
||||
|
||||
struct CDelta
|
||||
{
|
||||
unsigned _delta;
|
||||
Byte _state[DELTA_STATE_SIZE];
|
||||
|
||||
CDelta(): _delta(1) {}
|
||||
void DeltaInit() { Delta_Init(_state); }
|
||||
};
|
||||
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
|
||||
class CEncoder:
|
||||
public ICompressFilter,
|
||||
public ICompressSetCoderProperties,
|
||||
public ICompressWriteCoderProperties,
|
||||
CDelta,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP3(ICompressFilter, ICompressSetCoderProperties, ICompressWriteCoderProperties)
|
||||
INTERFACE_ICompressFilter(;)
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
|
||||
};
|
||||
|
||||
STDMETHODIMP CEncoder::Init()
|
||||
{
|
||||
DeltaInit();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
|
||||
{
|
||||
Delta_Encode(_state, _delta, data, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
|
||||
{
|
||||
UInt32 delta = _delta;
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = props[i];
|
||||
PROPID propID = propIDs[i];
|
||||
if (propID >= NCoderPropID::kReduceSize)
|
||||
continue;
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
switch (propID)
|
||||
{
|
||||
case NCoderPropID::kDefaultProp:
|
||||
delta = (UInt32)prop.ulVal;
|
||||
if (delta < 1 || delta > 256)
|
||||
return E_INVALIDARG;
|
||||
break;
|
||||
case NCoderPropID::kNumThreads: break;
|
||||
case NCoderPropID::kLevel: break;
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
_delta = delta;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
|
||||
{
|
||||
Byte prop = (Byte)(_delta - 1);
|
||||
return outStream->Write(&prop, 1, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class CDecoder:
|
||||
public ICompressFilter,
|
||||
public ICompressSetDecoderProperties2,
|
||||
CDelta,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(ICompressFilter, ICompressSetDecoderProperties2)
|
||||
INTERFACE_ICompressFilter(;)
|
||||
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
};
|
||||
|
||||
STDMETHODIMP CDecoder::Init()
|
||||
{
|
||||
DeltaInit();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
|
||||
{
|
||||
Delta_Decode(_state, _delta, data, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
|
||||
{
|
||||
if (size != 1)
|
||||
return E_INVALIDARG;
|
||||
_delta = (unsigned)props[0] + 1;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
REGISTER_FILTER_E(Delta,
|
||||
CDecoder(),
|
||||
CEncoder(),
|
||||
3, "Delta")
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,28 @@
|
||||
// DllExports2Compress.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/MyInitGuid.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
extern "C"
|
||||
BOOL WINAPI DllMain(
|
||||
#ifdef UNDER_CE
|
||||
HANDLE
|
||||
#else
|
||||
HINSTANCE
|
||||
#endif
|
||||
/* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
|
||||
|
||||
STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
|
||||
{
|
||||
return CreateCoder(clsid, iid, outObject);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// DllExportsCompress.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/MyInitGuid.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
static const unsigned kNumCodecsMax = 48;
|
||||
unsigned g_NumCodecs = 0;
|
||||
const CCodecInfo *g_Codecs[kNumCodecsMax];
|
||||
void RegisterCodec(const CCodecInfo *codecInfo) throw()
|
||||
{
|
||||
if (g_NumCodecs < kNumCodecsMax)
|
||||
g_Codecs[g_NumCodecs++] = codecInfo;
|
||||
}
|
||||
|
||||
static const unsigned kNumHashersMax = 16;
|
||||
unsigned g_NumHashers = 0;
|
||||
const CHasherInfo *g_Hashers[kNumHashersMax];
|
||||
void RegisterHasher(const CHasherInfo *hashInfo) throw()
|
||||
{
|
||||
if (g_NumHashers < kNumHashersMax)
|
||||
g_Hashers[g_NumHashers++] = hashInfo;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C"
|
||||
BOOL WINAPI DllMain(
|
||||
#ifdef UNDER_CE
|
||||
HANDLE
|
||||
#else
|
||||
HINSTANCE
|
||||
#endif
|
||||
, DWORD /* dwReason */, LPVOID /*lpReserved*/)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
|
||||
|
||||
STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
|
||||
{
|
||||
return CreateCoder(clsid, iid, outObject);
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
// Compress/HuffmanDecoder.h
|
||||
|
||||
#ifndef __COMPRESS_HUFFMAN_DECODER_H
|
||||
#define __COMPRESS_HUFFMAN_DECODER_H
|
||||
|
||||
#include "../../Common/MyTypes.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NHuffman {
|
||||
|
||||
const unsigned kNumPairLenBits = 4;
|
||||
const unsigned kPairLenMask = (1 << kNumPairLenBits) - 1;
|
||||
|
||||
template <unsigned kNumBitsMax, UInt32 m_NumSymbols, unsigned kNumTableBits = 9>
|
||||
class CDecoder
|
||||
{
|
||||
public:
|
||||
UInt32 _limits[kNumBitsMax + 2];
|
||||
UInt32 _poses[kNumBitsMax + 1];
|
||||
UInt16 _lens[1 << kNumTableBits];
|
||||
UInt16 _symbols[m_NumSymbols];
|
||||
|
||||
bool Build(const Byte *lens) throw()
|
||||
{
|
||||
UInt32 counts[kNumBitsMax + 1];
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i <= kNumBitsMax; i++)
|
||||
counts[i] = 0;
|
||||
|
||||
UInt32 sym;
|
||||
|
||||
for (sym = 0; sym < m_NumSymbols; sym++)
|
||||
counts[lens[sym]]++;
|
||||
|
||||
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
|
||||
|
||||
_limits[0] = 0;
|
||||
|
||||
UInt32 startPos = 0;
|
||||
UInt32 sum = 0;
|
||||
|
||||
for (i = 1; i <= kNumBitsMax; i++)
|
||||
{
|
||||
const UInt32 cnt = counts[i];
|
||||
startPos += cnt << (kNumBitsMax - i);
|
||||
if (startPos > kMaxValue)
|
||||
return false;
|
||||
_limits[i] = startPos;
|
||||
counts[i] = sum;
|
||||
_poses[i] = sum;
|
||||
sum += cnt;
|
||||
}
|
||||
|
||||
counts[0] = sum;
|
||||
_poses[0] = sum;
|
||||
_limits[kNumBitsMax + 1] = kMaxValue;
|
||||
|
||||
for (sym = 0; sym < m_NumSymbols; sym++)
|
||||
{
|
||||
unsigned len = lens[sym];
|
||||
if (len == 0)
|
||||
continue;
|
||||
|
||||
unsigned offset = counts[len]++;
|
||||
_symbols[offset] = (UInt16)sym;
|
||||
|
||||
if (len <= kNumTableBits)
|
||||
{
|
||||
offset -= _poses[len];
|
||||
UInt32 num = (UInt32)1 << (kNumTableBits - len);
|
||||
UInt16 val = (UInt16)((sym << kNumPairLenBits) | len);
|
||||
UInt16 *dest = _lens + (_limits[(size_t)len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
|
||||
for (UInt32 k = 0; k < num; k++)
|
||||
dest[k] = val;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool BuildFull(const Byte *lens, UInt32 numSymbols = m_NumSymbols) throw()
|
||||
{
|
||||
UInt32 counts[kNumBitsMax + 1];
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i <= kNumBitsMax; i++)
|
||||
counts[i] = 0;
|
||||
|
||||
UInt32 sym;
|
||||
|
||||
for (sym = 0; sym < numSymbols; sym++)
|
||||
counts[lens[sym]]++;
|
||||
|
||||
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
|
||||
|
||||
_limits[0] = 0;
|
||||
|
||||
UInt32 startPos = 0;
|
||||
UInt32 sum = 0;
|
||||
|
||||
for (i = 1; i <= kNumBitsMax; i++)
|
||||
{
|
||||
const UInt32 cnt = counts[i];
|
||||
startPos += cnt << (kNumBitsMax - i);
|
||||
if (startPos > kMaxValue)
|
||||
return false;
|
||||
_limits[i] = startPos;
|
||||
counts[i] = sum;
|
||||
_poses[i] = sum;
|
||||
sum += cnt;
|
||||
}
|
||||
|
||||
counts[0] = sum;
|
||||
_poses[0] = sum;
|
||||
_limits[kNumBitsMax + 1] = kMaxValue;
|
||||
|
||||
for (sym = 0; sym < numSymbols; sym++)
|
||||
{
|
||||
unsigned len = lens[sym];
|
||||
if (len == 0)
|
||||
continue;
|
||||
|
||||
unsigned offset = counts[len]++;
|
||||
_symbols[offset] = (UInt16)sym;
|
||||
|
||||
if (len <= kNumTableBits)
|
||||
{
|
||||
offset -= _poses[len];
|
||||
UInt32 num = (UInt32)1 << (kNumTableBits - len);
|
||||
UInt16 val = (UInt16)((sym << kNumPairLenBits) | len);
|
||||
UInt16 *dest = _lens + (_limits[(size_t)len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
|
||||
for (UInt32 k = 0; k < num; k++)
|
||||
dest[k] = val;
|
||||
}
|
||||
}
|
||||
|
||||
return startPos == kMaxValue;
|
||||
}
|
||||
|
||||
|
||||
template <class TBitDecoder>
|
||||
MY_FORCE_INLINE
|
||||
UInt32 Decode(TBitDecoder *bitStream) const
|
||||
{
|
||||
UInt32 val = bitStream->GetValue(kNumBitsMax);
|
||||
|
||||
if (val < _limits[kNumTableBits])
|
||||
{
|
||||
UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
|
||||
bitStream->MovePos((unsigned)(pair & kPairLenMask));
|
||||
return pair >> kNumPairLenBits;
|
||||
}
|
||||
|
||||
unsigned numBits;
|
||||
for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
|
||||
|
||||
if (numBits > kNumBitsMax)
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
bitStream->MovePos(numBits);
|
||||
UInt32 index = _poses[numBits] + ((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits));
|
||||
return _symbols[index];
|
||||
}
|
||||
|
||||
|
||||
template <class TBitDecoder>
|
||||
MY_FORCE_INLINE
|
||||
UInt32 DecodeFull(TBitDecoder *bitStream) const
|
||||
{
|
||||
UInt32 val = bitStream->GetValue(kNumBitsMax);
|
||||
|
||||
if (val < _limits[kNumTableBits])
|
||||
{
|
||||
UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
|
||||
bitStream->MovePos((unsigned)(pair & kPairLenMask));
|
||||
return pair >> kNumPairLenBits;
|
||||
}
|
||||
|
||||
unsigned numBits;
|
||||
for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
|
||||
|
||||
bitStream->MovePos(numBits);
|
||||
UInt32 index = _poses[numBits] + ((val - _limits[(size_t)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 counts[kNumBitsMax + 1];
|
||||
UInt32 _poses[kNumBitsMax + 1];
|
||||
UInt32 _limits[kNumBitsMax + 1];
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i <= kNumBitsMax; i++)
|
||||
counts[i] = 0;
|
||||
|
||||
UInt32 sym;
|
||||
|
||||
for (sym = 0; sym < m_NumSymbols; sym++)
|
||||
counts[lens[sym]]++;
|
||||
|
||||
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
|
||||
|
||||
_limits[0] = 0;
|
||||
|
||||
UInt32 startPos = 0;
|
||||
UInt32 sum = 0;
|
||||
|
||||
for (i = 1; i <= kNumBitsMax; i++)
|
||||
{
|
||||
const UInt32 cnt = counts[i];
|
||||
startPos += cnt << (kNumBitsMax - i);
|
||||
if (startPos > kMaxValue)
|
||||
return false;
|
||||
_limits[i] = startPos;
|
||||
counts[i] = sum;
|
||||
_poses[i] = sum;
|
||||
sum += cnt;
|
||||
}
|
||||
|
||||
counts[0] = sum;
|
||||
_poses[0] = sum;
|
||||
|
||||
for (sym = 0; sym < m_NumSymbols; sym++)
|
||||
{
|
||||
unsigned len = lens[sym];
|
||||
if (len == 0)
|
||||
continue;
|
||||
|
||||
unsigned offset = counts[len]++;
|
||||
|
||||
{
|
||||
offset -= _poses[len];
|
||||
UInt32 num = (UInt32)1 << (kNumBitsMax - len);
|
||||
Byte val = (Byte)((sym << 3) | len);
|
||||
Byte *dest = _lens + (_limits[(size_t)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 Decode(TBitDecoder *bitStream) const
|
||||
{
|
||||
UInt32 val = bitStream->GetValue(7);
|
||||
UInt32 pair = _lens[val];
|
||||
bitStream->MovePos((unsigned)(pair & 0x7));
|
||||
return pair >> 3;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,258 @@
|
||||
// ImplodeDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/Defs.h"
|
||||
|
||||
#include "ImplodeDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NImplode {
|
||||
namespace NDecoder {
|
||||
|
||||
bool CHuffmanDecoder::Build(const Byte *lens, unsigned numSymbols) throw()
|
||||
{
|
||||
unsigned counts[kNumHuffmanBits + 1];
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i <= kNumHuffmanBits; i++)
|
||||
counts[i] = 0;
|
||||
|
||||
unsigned sym;
|
||||
for (sym = 0; sym < numSymbols; sym++)
|
||||
counts[lens[sym]]++;
|
||||
|
||||
const UInt32 kMaxValue = (UInt32)1 << kNumHuffmanBits;
|
||||
|
||||
// _limits[0] = kMaxValue;
|
||||
|
||||
UInt32 startPos = kMaxValue;
|
||||
UInt32 sum = 0;
|
||||
|
||||
for (i = 1; i <= kNumHuffmanBits; i++)
|
||||
{
|
||||
const UInt32 cnt = counts[i];
|
||||
const UInt32 range = cnt << (kNumHuffmanBits - i);
|
||||
if (startPos < range)
|
||||
return false;
|
||||
startPos -= range;
|
||||
_limits[i] = startPos;
|
||||
_poses[i] = sum;
|
||||
sum += cnt;
|
||||
counts[i] = sum;
|
||||
}
|
||||
|
||||
// counts[0] += sum;
|
||||
|
||||
if (startPos != 0)
|
||||
return false;
|
||||
|
||||
for (sym = 0; sym < numSymbols; sym++)
|
||||
{
|
||||
unsigned len = lens[sym];
|
||||
if (len != 0)
|
||||
_symbols[--counts[len]] = (Byte)sym;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
UInt32 CHuffmanDecoder::Decode(CInBit *inStream) const throw()
|
||||
{
|
||||
UInt32 val = inStream->GetValue(kNumHuffmanBits);
|
||||
unsigned numBits;
|
||||
for (numBits = 1; val < _limits[numBits]; numBits++);
|
||||
UInt32 sym = _symbols[_poses[numBits] + ((val - _limits[numBits]) >> (kNumHuffmanBits - numBits))];
|
||||
inStream->MovePos(numBits);
|
||||
return sym;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const unsigned kNumLenDirectBits = 8;
|
||||
|
||||
static const unsigned kNumDistDirectBitsSmall = 6;
|
||||
static const unsigned kNumDistDirectBitsBig = 7;
|
||||
|
||||
static const unsigned kLitTableSize = (1 << 8);
|
||||
static const unsigned kDistTableSize = 64;
|
||||
static const unsigned kLenTableSize = 64;
|
||||
|
||||
static const UInt32 kHistorySize = (1 << kNumDistDirectBitsBig) * kDistTableSize; // 8 KB
|
||||
|
||||
|
||||
CCoder::CCoder():
|
||||
_fullStreamMode(false),
|
||||
_flags(0)
|
||||
{}
|
||||
|
||||
|
||||
bool CCoder::BuildHuff(CHuffmanDecoder &decoder, unsigned numSymbols)
|
||||
{
|
||||
Byte levels[kMaxHuffTableSize];
|
||||
unsigned numRecords = (unsigned)_inBitStream.ReadAlignedByte() + 1;
|
||||
unsigned index = 0;
|
||||
do
|
||||
{
|
||||
unsigned b = (unsigned)_inBitStream.ReadAlignedByte();
|
||||
Byte level = (Byte)((b & 0xF) + 1);
|
||||
unsigned rep = ((unsigned)b >> 4) + 1;
|
||||
if (index + rep > numSymbols)
|
||||
return false;
|
||||
for (unsigned j = 0; j < rep; j++)
|
||||
levels[index++] = level;
|
||||
}
|
||||
while (--numRecords);
|
||||
|
||||
if (index != numSymbols)
|
||||
return false;
|
||||
return decoder.Build(levels, numSymbols);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_inBitStream.Create(1 << 18))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_outWindowStream.Create(kHistorySize << 1)) // 16 KB
|
||||
return E_OUTOFMEMORY;
|
||||
if (!outSize)
|
||||
return E_INVALIDARG;
|
||||
|
||||
_outWindowStream.SetStream(outStream);
|
||||
_outWindowStream.Init(false);
|
||||
_inBitStream.SetStream(inStream);
|
||||
_inBitStream.Init();
|
||||
|
||||
const unsigned numDistDirectBits = (_flags & 2) ?
|
||||
kNumDistDirectBitsBig:
|
||||
kNumDistDirectBitsSmall;
|
||||
const bool literalsOn = ((_flags & 4) != 0);
|
||||
const UInt32 minMatchLen = (literalsOn ? 3 : 2);
|
||||
|
||||
if (literalsOn)
|
||||
if (!BuildHuff(_litDecoder, kLitTableSize))
|
||||
return S_FALSE;
|
||||
if (!BuildHuff(_lenDecoder, kLenTableSize))
|
||||
return S_FALSE;
|
||||
if (!BuildHuff(_distDecoder, kDistTableSize))
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 prevProgress = 0;
|
||||
bool moreOut = false;
|
||||
UInt64 pos = 0, unPackSize = *outSize;
|
||||
|
||||
while (pos < unPackSize)
|
||||
{
|
||||
if (progress && (pos - prevProgress) >= (1 << 18))
|
||||
{
|
||||
const UInt64 packSize = _inBitStream.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &pos));
|
||||
prevProgress = pos;
|
||||
}
|
||||
|
||||
if (_inBitStream.ReadBits(1) != 0)
|
||||
{
|
||||
Byte b;
|
||||
if (literalsOn)
|
||||
{
|
||||
UInt32 sym = _litDecoder.Decode(&_inBitStream);
|
||||
// if (sym >= kLitTableSize) break;
|
||||
b = (Byte)sym;
|
||||
}
|
||||
else
|
||||
b = (Byte)_inBitStream.ReadBits(8);
|
||||
_outWindowStream.PutByte(b);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 lowDistBits = _inBitStream.ReadBits(numDistDirectBits);
|
||||
UInt32 dist = _distDecoder.Decode(&_inBitStream);
|
||||
// if (dist >= kDistTableSize) break;
|
||||
dist = (dist << numDistDirectBits) + lowDistBits;
|
||||
UInt32 len = _lenDecoder.Decode(&_inBitStream);
|
||||
// if (len >= kLenTableSize) break;
|
||||
if (len == kLenTableSize - 1)
|
||||
len += _inBitStream.ReadBits(kNumLenDirectBits);
|
||||
len += minMatchLen;
|
||||
|
||||
{
|
||||
const UInt64 limit = unPackSize - pos;
|
||||
if (len > limit)
|
||||
{
|
||||
moreOut = true;
|
||||
len = (UInt32)limit;
|
||||
}
|
||||
}
|
||||
|
||||
while (dist >= pos && len != 0)
|
||||
{
|
||||
_outWindowStream.PutByte(0);
|
||||
pos++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
{
|
||||
_outWindowStream.CopyBlock(dist, len);
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT res = _outWindowStream.Flush();
|
||||
|
||||
if (res == S_OK)
|
||||
{
|
||||
if (_fullStreamMode)
|
||||
{
|
||||
if (moreOut)
|
||||
res = S_FALSE;
|
||||
if (inSize && *inSize != _inBitStream.GetProcessedSize())
|
||||
res = S_FALSE;
|
||||
}
|
||||
if (pos != unPackSize)
|
||||
res = S_FALSE;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::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 CSystemException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
return E_NOTIMPL;
|
||||
_flags = data[0];
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::SetFinishMode(UInt32 finishMode)
|
||||
{
|
||||
_fullStreamMode = (finishMode != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
*value = _inBitStream.GetProcessedSize();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -0,0 +1,73 @@
|
||||
// ImplodeDecoder.h
|
||||
|
||||
#ifndef __COMPRESS_IMPLODE_DECODER_H
|
||||
#define __COMPRESS_IMPLODE_DECODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
|
||||
#include "BitlDecoder.h"
|
||||
#include "LzOutWindow.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NImplode {
|
||||
namespace NDecoder {
|
||||
|
||||
typedef NBitl::CDecoder<CInBuffer> CInBit;
|
||||
|
||||
const unsigned kNumHuffmanBits = 16;
|
||||
const unsigned kMaxHuffTableSize = 1 << 8;
|
||||
|
||||
class CHuffmanDecoder
|
||||
{
|
||||
UInt32 _limits[kNumHuffmanBits + 1];
|
||||
UInt32 _poses[kNumHuffmanBits + 1];
|
||||
Byte _symbols[kMaxHuffTableSize];
|
||||
public:
|
||||
bool Build(const Byte *lens, unsigned numSymbols) throw();
|
||||
UInt32 Decode(CInBit *inStream) const throw();
|
||||
};
|
||||
|
||||
|
||||
class CCoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetDecoderProperties2,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzOutWindow _outWindowStream;
|
||||
CInBit _inBitStream;
|
||||
|
||||
CHuffmanDecoder _litDecoder;
|
||||
CHuffmanDecoder _lenDecoder;
|
||||
CHuffmanDecoder _distDecoder;
|
||||
|
||||
Byte _flags;
|
||||
bool _fullStreamMode;
|
||||
|
||||
bool BuildHuff(CHuffmanDecoder &table, unsigned numSymbols);
|
||||
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP3(
|
||||
ICompressSetDecoderProperties2,
|
||||
ICompressSetFinishMode,
|
||||
ICompressGetInStreamProcessedSize)
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
|
||||
CCoder();
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
// ImplodeHuffmanDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
@@ -0,0 +1,6 @@
|
||||
// ImplodeHuffmanDecoder.h
|
||||
|
||||
#ifndef __IMPLODE_HUFFMAN_DECODER_H
|
||||
#define __IMPLODE_HUFFMAN_DECODER_H
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
// LzOutWindow.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "LzOutWindow.h"
|
||||
|
||||
void CLzOutWindow::Init(bool solid) throw()
|
||||
{
|
||||
if (!solid)
|
||||
COutBuffer::Init();
|
||||
#ifdef _NO_EXCEPTIONS
|
||||
ErrorCode = S_OK;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
// LzOutWindow.h
|
||||
|
||||
#ifndef __LZ_OUT_WINDOW_H
|
||||
#define __LZ_OUT_WINDOW_H
|
||||
|
||||
#include "../Common/OutBuffer.h"
|
||||
|
||||
#ifndef _NO_EXCEPTIONS
|
||||
typedef COutBufferException CLzOutWindowException;
|
||||
#endif
|
||||
|
||||
class CLzOutWindow: public COutBuffer
|
||||
{
|
||||
public:
|
||||
void Init(bool solid = false) throw();
|
||||
|
||||
// distance >= 0, len > 0,
|
||||
bool CopyBlock(UInt32 distance, UInt32 len)
|
||||
{
|
||||
UInt32 pos = _pos - distance - 1;
|
||||
if (distance >= _pos)
|
||||
{
|
||||
if (!_overDict || distance >= _bufSize)
|
||||
return false;
|
||||
pos += _bufSize;
|
||||
}
|
||||
if (_limitPos - _pos > len && _bufSize - pos > len)
|
||||
{
|
||||
const Byte *src = _buf + pos;
|
||||
Byte *dest = _buf + _pos;
|
||||
_pos += len;
|
||||
do
|
||||
*dest++ = *src++;
|
||||
while (--len != 0);
|
||||
}
|
||||
else do
|
||||
{
|
||||
UInt32 pos2;
|
||||
if (pos == _bufSize)
|
||||
pos = 0;
|
||||
pos2 = _pos;
|
||||
_buf[pos2++] = _buf[pos++];
|
||||
_pos = pos2;
|
||||
if (pos2 == _limitPos)
|
||||
FlushWithCheck();
|
||||
}
|
||||
while (--len != 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PutByte(Byte b)
|
||||
{
|
||||
UInt32 pos = _pos;
|
||||
_buf[pos++] = b;
|
||||
_pos = pos;
|
||||
if (pos == _limitPos)
|
||||
FlushWithCheck();
|
||||
}
|
||||
|
||||
void PutBytes(const Byte *data, UInt32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
UInt32 pos = _pos;
|
||||
Byte *buf = _buf;
|
||||
buf[pos++] = *data++;
|
||||
size--;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 limitPos = _limitPos;
|
||||
UInt32 rem = limitPos - pos;
|
||||
if (rem == 0)
|
||||
{
|
||||
_pos = pos;
|
||||
FlushWithCheck();
|
||||
pos = _pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
break;
|
||||
|
||||
if (rem > size)
|
||||
rem = size;
|
||||
size -= rem;
|
||||
do
|
||||
buf[pos++] = *data++;
|
||||
while (--rem);
|
||||
}
|
||||
_pos = pos;
|
||||
}
|
||||
|
||||
Byte GetByte(UInt32 distance) const
|
||||
{
|
||||
UInt32 pos = _pos - distance - 1;
|
||||
if (distance >= _pos)
|
||||
pos += _bufSize;
|
||||
return _buf[pos];
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,925 @@
|
||||
// LzfseDecoder.cpp
|
||||
|
||||
/*
|
||||
This code implements LZFSE data decompressing.
|
||||
The code from "LZFSE compression library" was used.
|
||||
|
||||
2018 : Igor Pavlov : BSD 3-clause License : the code in this file
|
||||
2015-2017 : Apple Inc : BSD 3-clause License : original "LZFSE compression library" code
|
||||
|
||||
The code in the "LZFSE compression library" is licensed under the "BSD 3-clause License":
|
||||
----
|
||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #define SHOW_DEBUG_INFO
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef SHOW_DEBUG_INFO
|
||||
#define PRF(x) x
|
||||
#else
|
||||
#define PRF(x)
|
||||
#endif
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "LzfseDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzfse {
|
||||
|
||||
static const Byte kSignature_LZFSE_V1 = 0x31; // '1'
|
||||
static const Byte kSignature_LZFSE_V2 = 0x32; // '2'
|
||||
|
||||
|
||||
HRESULT CDecoder::GetUInt32(UInt32 &val)
|
||||
{
|
||||
Byte b[4];
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
if (!m_InStream.ReadByte(b[i]))
|
||||
return S_FALSE;
|
||||
val = GetUi32(b);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CDecoder::DecodeUncompressed(UInt32 unpackSize)
|
||||
{
|
||||
PRF(printf("\nUncompressed %7u\n", unpackSize));
|
||||
|
||||
const unsigned kBufSize = 1 << 8;
|
||||
Byte buf[kBufSize];
|
||||
for (;;)
|
||||
{
|
||||
if (unpackSize == 0)
|
||||
return S_OK;
|
||||
UInt32 cur = unpackSize;
|
||||
if (cur > kBufSize)
|
||||
cur = kBufSize;
|
||||
UInt32 cur2 = (UInt32)m_InStream.ReadBytes(buf, cur);
|
||||
m_OutWindowStream.PutBytes(buf, cur2);
|
||||
if (cur != cur2)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize)
|
||||
{
|
||||
UInt32 packSize;
|
||||
RINOK(GetUInt32(packSize));
|
||||
|
||||
PRF(printf("\nLZVN %7u %7u", unpackSize, packSize));
|
||||
|
||||
UInt32 D = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (packSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b;
|
||||
if (!m_InStream.ReadByte(b))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
|
||||
UInt32 M;
|
||||
UInt32 L;
|
||||
|
||||
if (b >= 0xE0)
|
||||
{
|
||||
/*
|
||||
large L - 11100000 LLLLLLLL <LITERALS>
|
||||
small L - 1110LLLL <LITERALS>
|
||||
|
||||
large Rep - 11110000 MMMMMMMM
|
||||
small Rep - 1111MMMM
|
||||
*/
|
||||
|
||||
M = b & 0xF;
|
||||
if (M == 0)
|
||||
{
|
||||
if (packSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b1;
|
||||
if (!m_InStream.ReadByte(b1))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
M = (UInt32)b1 + 16;
|
||||
}
|
||||
L = 0;
|
||||
if ((b & 0x10) == 0)
|
||||
{
|
||||
// Literals only
|
||||
L = M;
|
||||
M = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ERROR codes
|
||||
else if ((b & 0xF0) == 0x70) // 0111xxxx
|
||||
return S_FALSE;
|
||||
else if ((b & 0xF0) == 0xD0) // 1101xxxx
|
||||
return S_FALSE;
|
||||
|
||||
else
|
||||
{
|
||||
if ((b & 0xE0) == 0xA0)
|
||||
{
|
||||
// medium - 101LLMMM DDDDDDMM DDDDDDDD <LITERALS>
|
||||
if (packSize < 2)
|
||||
return S_FALSE;
|
||||
Byte b1;
|
||||
if (!m_InStream.ReadByte(b1))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
|
||||
Byte b2;
|
||||
if (!m_InStream.ReadByte(b2))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
L = (((UInt32)b >> 3) & 3);
|
||||
M = (((UInt32)b & 7) << 2) + (b1 & 3);
|
||||
D = ((UInt32)b1 >> 2) + ((UInt32)b2 << 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
L = (UInt32)b >> 6;
|
||||
M = ((UInt32)b >> 3) & 7;
|
||||
if ((b & 0x7) == 6)
|
||||
{
|
||||
// REP - LLMMM110 <LITERALS>
|
||||
if (L == 0)
|
||||
{
|
||||
// spec
|
||||
if (M == 0)
|
||||
break; // EOS
|
||||
if (M <= 2)
|
||||
continue; // NOP
|
||||
return S_FALSE; // UNDEFINED
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b1;
|
||||
if (!m_InStream.ReadByte(b1))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
|
||||
// large - LLMMM111 DDDDDDDD DDDDDDDD <LITERALS>
|
||||
// small - LLMMMDDD DDDDDDDD <LITERALS>
|
||||
D = ((UInt32)b & 7);
|
||||
if (D == 7)
|
||||
{
|
||||
if (packSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b2;
|
||||
if (!m_InStream.ReadByte(b2))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
D = b2;
|
||||
}
|
||||
D = (D << 8) + b1;
|
||||
}
|
||||
}
|
||||
|
||||
M += 3;
|
||||
}
|
||||
{
|
||||
for (unsigned i = 0; i < L; i++)
|
||||
{
|
||||
if (packSize == 0 || unpackSize == 0)
|
||||
return S_FALSE;
|
||||
Byte b1;
|
||||
if (!m_InStream.ReadByte(b1))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
m_OutWindowStream.PutByte(b1);
|
||||
unpackSize--;
|
||||
}
|
||||
}
|
||||
|
||||
if (M != 0)
|
||||
{
|
||||
if (unpackSize == 0 || D == 0)
|
||||
return S_FALSE;
|
||||
unsigned cur = M;
|
||||
if (cur > unpackSize)
|
||||
cur = (unsigned)unpackSize;
|
||||
if (!m_OutWindowStream.CopyBlock(D - 1, cur))
|
||||
return S_FALSE;
|
||||
unpackSize -= cur;
|
||||
if (cur != M)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (unpackSize != 0)
|
||||
return S_FALSE;
|
||||
|
||||
// LZVN encoder writes 7 additional zero bytes
|
||||
if (packSize != 7)
|
||||
return S_FALSE;
|
||||
do
|
||||
{
|
||||
Byte b;
|
||||
if (!m_InStream.ReadByte(b))
|
||||
return S_FALSE;
|
||||
packSize--;
|
||||
if (b != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
while (packSize != 0);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------- LZFSE ----------
|
||||
|
||||
#define MATCHES_PER_BLOCK 10000
|
||||
#define LITERALS_PER_BLOCK (4 * MATCHES_PER_BLOCK)
|
||||
|
||||
#define NUM_L_SYMBOLS 20
|
||||
#define NUM_M_SYMBOLS 20
|
||||
#define NUM_D_SYMBOLS 64
|
||||
#define NUM_LIT_SYMBOLS 256
|
||||
|
||||
#define NUM_SYMBOLS ( \
|
||||
NUM_L_SYMBOLS + \
|
||||
NUM_M_SYMBOLS + \
|
||||
NUM_D_SYMBOLS + \
|
||||
NUM_LIT_SYMBOLS)
|
||||
|
||||
#define NUM_L_STATES (1 << 6)
|
||||
#define NUM_M_STATES (1 << 6)
|
||||
#define NUM_D_STATES (1 << 8)
|
||||
#define NUM_LIT_STATES (1 << 10)
|
||||
|
||||
|
||||
typedef UInt32 CFseState;
|
||||
|
||||
|
||||
static UInt32 SumFreqs(const UInt16 *freqs, unsigned num)
|
||||
{
|
||||
UInt32 sum = 0;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
sum += (UInt32)freqs[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
static MY_FORCE_INLINE unsigned CountZeroBits(UInt32 val, UInt32 mask)
|
||||
{
|
||||
for (unsigned i = 0;;)
|
||||
{
|
||||
if (val & mask)
|
||||
return i;
|
||||
i++;
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static MY_FORCE_INLINE void InitLitTable(const UInt16 *freqs, UInt32 *table)
|
||||
{
|
||||
for (unsigned i = 0; i < NUM_LIT_SYMBOLS; i++)
|
||||
{
|
||||
unsigned f = freqs[i];
|
||||
if (f == 0)
|
||||
continue;
|
||||
|
||||
// 0 < f <= numStates
|
||||
// 0 <= k <= numStatesLog
|
||||
// numStates <= (f<<k) < numStates * 2
|
||||
// 0 < j0 <= f
|
||||
// (f + j0) = next_power_of_2 for f
|
||||
unsigned k = CountZeroBits(f, NUM_LIT_STATES);
|
||||
unsigned j0 = (((unsigned)NUM_LIT_STATES * 2) >> k) - f;
|
||||
|
||||
/*
|
||||
CEntry
|
||||
{
|
||||
Byte k;
|
||||
Byte symbol;
|
||||
UInt16 delta;
|
||||
};
|
||||
*/
|
||||
|
||||
UInt32 e = ((UInt32)i << 8) + k;
|
||||
k += 16;
|
||||
UInt32 d = e + ((UInt32)f << k) - ((UInt32)NUM_LIT_STATES << 16);
|
||||
UInt32 step = (UInt32)1 << k;
|
||||
|
||||
unsigned j = 0;
|
||||
do
|
||||
{
|
||||
*table++ = d;
|
||||
d += step;
|
||||
}
|
||||
while (++j < j0);
|
||||
|
||||
e--;
|
||||
step >>= 1;
|
||||
|
||||
for (j = j0; j < f; j++)
|
||||
{
|
||||
*table++ = e;
|
||||
e += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Byte totalBits;
|
||||
Byte extraBits;
|
||||
UInt16 delta;
|
||||
UInt32 vbase;
|
||||
} CExtraEntry;
|
||||
|
||||
|
||||
static void InitExtraDecoderTable(unsigned numStates,
|
||||
unsigned numSymbols,
|
||||
const UInt16 *freqs,
|
||||
const Byte *vbits,
|
||||
CExtraEntry *table)
|
||||
{
|
||||
UInt32 vbase = 0;
|
||||
|
||||
for (unsigned i = 0; i < numSymbols; i++)
|
||||
{
|
||||
unsigned f = freqs[i];
|
||||
unsigned extraBits = vbits[i];
|
||||
|
||||
if (f != 0)
|
||||
{
|
||||
unsigned k = CountZeroBits(f, numStates);
|
||||
unsigned j0 = ((2 * numStates) >> k) - f;
|
||||
|
||||
unsigned j = 0;
|
||||
do
|
||||
{
|
||||
CExtraEntry *e = table++;
|
||||
e->totalBits = (Byte)(k + extraBits);
|
||||
e->extraBits = (Byte)extraBits;
|
||||
e->delta = (UInt16)(((f + j) << k) - numStates);
|
||||
e->vbase = vbase;
|
||||
}
|
||||
while (++j < j0);
|
||||
|
||||
f -= j0;
|
||||
k--;
|
||||
|
||||
for (j = 0; j < f; j++)
|
||||
{
|
||||
CExtraEntry *e = table++;
|
||||
e->totalBits = (Byte)(k + extraBits);
|
||||
e->extraBits = (Byte)extraBits;
|
||||
e->delta = (UInt16)(j << k);
|
||||
e->vbase = vbase;
|
||||
}
|
||||
}
|
||||
|
||||
vbase += ((UInt32)1 << extraBits);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const Byte k_L_extra[NUM_L_SYMBOLS] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 8
|
||||
};
|
||||
|
||||
static const Byte k_M_extra[NUM_M_SYMBOLS] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11
|
||||
};
|
||||
|
||||
static const Byte k_D_extra[NUM_D_SYMBOLS] =
|
||||
{
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ---------- CBitStream ----------
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 accum;
|
||||
unsigned numBits; // [0, 31] - Number of valid bits in (accum), other bits are 0
|
||||
} CBitStream;
|
||||
|
||||
|
||||
static MY_FORCE_INLINE int FseInStream_Init(CBitStream *s,
|
||||
int n, // [-7, 0], (-n == number_of_unused_bits) in last byte
|
||||
const Byte **pbuf)
|
||||
{
|
||||
*pbuf -= 4;
|
||||
s->accum = GetUi32(*pbuf);
|
||||
if (n)
|
||||
{
|
||||
s->numBits = n + 32;
|
||||
if ((s->accum >> s->numBits) != 0)
|
||||
return -1; // ERROR, encoder should have zeroed the upper bits
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbuf += 1;
|
||||
s->accum >>= 8;
|
||||
s->numBits = 24;
|
||||
}
|
||||
return 0; // OK
|
||||
}
|
||||
|
||||
|
||||
// 0 <= numBits < 32
|
||||
#define mask31(x, numBits) ((x) & (((UInt32)1 << (numBits)) - 1))
|
||||
|
||||
#define FseInStream_FLUSH \
|
||||
{ unsigned nbits = (31 - in.numBits) & -8; \
|
||||
if (nbits) { \
|
||||
buf -= (nbits >> 3); \
|
||||
if (buf < buf_check) return S_FALSE; \
|
||||
UInt32 v = GetUi32(buf); \
|
||||
in.accum = (in.accum << nbits) | mask31(v, nbits); \
|
||||
in.numBits += nbits; }}
|
||||
|
||||
|
||||
|
||||
static MY_FORCE_INLINE UInt32 BitStream_Pull(CBitStream *s, unsigned numBits)
|
||||
{
|
||||
s->numBits -= numBits;
|
||||
UInt32 v = s->accum >> s->numBits;
|
||||
s->accum = mask31(s->accum, s->numBits);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
#define DECODE_LIT(dest, pstate) { \
|
||||
UInt32 e = lit_decoder[pstate]; \
|
||||
pstate = (CFseState)((e >> 16) + BitStream_Pull(&in, e & 0xff)); \
|
||||
dest = (Byte)(e >> 8); }
|
||||
|
||||
|
||||
static MY_FORCE_INLINE UInt32 FseDecodeExtra(CFseState *pstate,
|
||||
const CExtraEntry *table,
|
||||
CBitStream *s)
|
||||
{
|
||||
const CExtraEntry *e = &table[*pstate];
|
||||
UInt32 v = BitStream_Pull(s, e->totalBits);
|
||||
unsigned extraBits = e->extraBits;
|
||||
*pstate = (CFseState)(e->delta + (v >> extraBits));
|
||||
return e->vbase + mask31(v, extraBits);
|
||||
}
|
||||
|
||||
|
||||
#define freqs_L (freqs)
|
||||
#define freqs_M (freqs_L + NUM_L_SYMBOLS)
|
||||
#define freqs_D (freqs_M + NUM_M_SYMBOLS)
|
||||
#define freqs_LIT (freqs_D + NUM_D_SYMBOLS)
|
||||
|
||||
#define GET_BITS_64(v, offset, num, dest) dest = (UInt32) ((v >> (offset)) & ((1 << (num)) - 1));
|
||||
#define GET_BITS_32(v, offset, num, dest) dest = (CFseState)((v >> (offset)) & ((1 << (num)) - 1));
|
||||
|
||||
|
||||
HRESULT CDecoder::DecodeLzfse(UInt32 unpackSize, Byte version)
|
||||
{
|
||||
PRF(printf("\nLZFSE-%d %7u", version - '0', unpackSize));
|
||||
|
||||
UInt32 numLiterals;
|
||||
UInt32 litPayloadSize;
|
||||
Int32 literal_bits;
|
||||
|
||||
UInt32 lit_state_0;
|
||||
UInt32 lit_state_1;
|
||||
UInt32 lit_state_2;
|
||||
UInt32 lit_state_3;
|
||||
|
||||
UInt32 numMatches;
|
||||
UInt32 lmdPayloadSize;
|
||||
Int32 lmd_bits;
|
||||
|
||||
CFseState l_state;
|
||||
CFseState m_state;
|
||||
CFseState d_state;
|
||||
|
||||
UInt16 freqs[NUM_SYMBOLS];
|
||||
|
||||
if (version == kSignature_LZFSE_V1)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
// we need examples to test LZFSE-V1 code
|
||||
/*
|
||||
const unsigned k_v1_SubHeaderSize = 7 * 4 + 7 * 2;
|
||||
const unsigned k_v1_HeaderSize = k_v1_SubHeaderSize + NUM_SYMBOLS * 2;
|
||||
_buffer.AllocAtLeast(k_v1_HeaderSize);
|
||||
if (m_InStream.ReadBytes(_buffer, k_v1_HeaderSize) != k_v1_HeaderSize)
|
||||
return S_FALSE;
|
||||
|
||||
const Byte *buf = _buffer;
|
||||
#define GET_32(offs, dest) dest = GetUi32(buf + offs)
|
||||
#define GET_16(offs, dest) dest = GetUi16(buf + offs)
|
||||
|
||||
UInt32 payload_bytes;
|
||||
GET_32(0, payload_bytes);
|
||||
GET_32(4, numLiterals);
|
||||
GET_32(8, numMatches);
|
||||
GET_32(12, litPayloadSize);
|
||||
GET_32(16, lmdPayloadSize);
|
||||
if (litPayloadSize > (1 << 20) || lmdPayloadSize > (1 << 20))
|
||||
return S_FALSE;
|
||||
GET_32(20, literal_bits);
|
||||
if (literal_bits < -7 || literal_bits > 0)
|
||||
return S_FALSE;
|
||||
|
||||
GET_16(24, lit_state_0);
|
||||
GET_16(26, lit_state_1);
|
||||
GET_16(28, lit_state_2);
|
||||
GET_16(30, lit_state_3);
|
||||
|
||||
GET_32(32, lmd_bits);
|
||||
if (lmd_bits < -7 || lmd_bits > 0)
|
||||
return S_FALSE;
|
||||
|
||||
GET_16(36, l_state);
|
||||
GET_16(38, m_state);
|
||||
GET_16(40, d_state);
|
||||
|
||||
for (unsigned i = 0; i < NUM_SYMBOLS; i++)
|
||||
freqs[i] = GetUi16(buf + k_v1_SubHeaderSize + i * 2);
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 headerSize;
|
||||
{
|
||||
const unsigned kPreHeaderSize = 4 * 2; // signature and upackSize
|
||||
const unsigned kHeaderSize = 8 * 3;
|
||||
Byte temp[kHeaderSize];
|
||||
if (m_InStream.ReadBytes(temp, kHeaderSize) != kHeaderSize)
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 v;
|
||||
|
||||
v = GetUi64(temp);
|
||||
GET_BITS_64(v, 0, 20, numLiterals);
|
||||
GET_BITS_64(v, 20, 20, litPayloadSize);
|
||||
GET_BITS_64(v, 40, 20, numMatches);
|
||||
GET_BITS_64(v, 60, 3 + 1, literal_bits); // (NumberOfUsedBits - 1)
|
||||
literal_bits -= 7; // (-NumberOfUnusedBits)
|
||||
if (literal_bits > 0)
|
||||
return S_FALSE;
|
||||
// GET_BITS_64(v, 63, 1, unused);
|
||||
|
||||
v = GetUi64(temp + 8);
|
||||
GET_BITS_64(v, 0, 10, lit_state_0);
|
||||
GET_BITS_64(v, 10, 10, lit_state_1);
|
||||
GET_BITS_64(v, 20, 10, lit_state_2);
|
||||
GET_BITS_64(v, 30, 10, lit_state_3);
|
||||
GET_BITS_64(v, 40, 20, lmdPayloadSize);
|
||||
GET_BITS_64(v, 60, 3 + 1, lmd_bits);
|
||||
lmd_bits -= 7;
|
||||
if (lmd_bits > 0)
|
||||
return S_FALSE;
|
||||
// GET_BITS_64(v, 63, 1, unused)
|
||||
|
||||
UInt32 v32 = GetUi32(temp + 20);
|
||||
// (total header size in bytes; this does not
|
||||
// correspond to a field in the uncompressed header version,
|
||||
// but is required; we wouldn't know the size of the
|
||||
// compresssed header otherwise.
|
||||
GET_BITS_32(v32, 0, 10, l_state);
|
||||
GET_BITS_32(v32, 10, 10, m_state);
|
||||
GET_BITS_32(v32, 20, 10 + 2, d_state);
|
||||
// GET_BITS_64(v, 62, 2, unused);
|
||||
|
||||
headerSize = GetUi32(temp + 16);
|
||||
if (headerSize <= kPreHeaderSize + kHeaderSize)
|
||||
return S_FALSE;
|
||||
headerSize -= kPreHeaderSize + kHeaderSize;
|
||||
}
|
||||
|
||||
// no freqs case is not allowed ?
|
||||
// memset(freqs, 0, sizeof(freqs));
|
||||
// if (headerSize != 0)
|
||||
{
|
||||
static const Byte numBitsTable[32] =
|
||||
{
|
||||
2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14,
|
||||
2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14
|
||||
};
|
||||
|
||||
static const Byte valueTable[32] =
|
||||
{
|
||||
0, 2, 1, 4, 0, 3, 1, 8, 0, 2, 1, 5, 0, 3, 1, 24,
|
||||
0, 2, 1, 6, 0, 3, 1, 8, 0, 2, 1, 7, 0, 3, 1, 24
|
||||
};
|
||||
|
||||
UInt32 accum = 0;
|
||||
unsigned numBits = 0;
|
||||
|
||||
for (unsigned i = 0; i < NUM_SYMBOLS; i++)
|
||||
{
|
||||
while (numBits <= 14 && headerSize != 0)
|
||||
{
|
||||
Byte b;
|
||||
if (!m_InStream.ReadByte(b))
|
||||
return S_FALSE;
|
||||
accum |= (UInt32)b << numBits;
|
||||
numBits += 8;
|
||||
headerSize--;
|
||||
}
|
||||
|
||||
unsigned b = (unsigned)accum & 31;
|
||||
unsigned n = numBitsTable[b];
|
||||
if (numBits < n)
|
||||
return S_FALSE;
|
||||
numBits -= n;
|
||||
UInt32 f = valueTable[b];
|
||||
if (n >= 8)
|
||||
f += ((accum >> 4) & (0x3ff >> (14 - n)));
|
||||
accum >>= n;
|
||||
freqs[i] = (UInt16)f;
|
||||
}
|
||||
|
||||
if (numBits >= 8 || headerSize != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
PRF(printf(" Literals=%6u Matches=%6u", numLiterals, numMatches));
|
||||
|
||||
if (numLiterals > LITERALS_PER_BLOCK
|
||||
|| (numLiterals & 3) != 0
|
||||
|| numMatches > MATCHES_PER_BLOCK
|
||||
|| lit_state_0 >= NUM_LIT_STATES
|
||||
|| lit_state_1 >= NUM_LIT_STATES
|
||||
|| lit_state_2 >= NUM_LIT_STATES
|
||||
|| lit_state_3 >= NUM_LIT_STATES
|
||||
|| l_state >= NUM_L_STATES
|
||||
|| m_state >= NUM_M_STATES
|
||||
|| d_state >= NUM_D_STATES)
|
||||
return S_FALSE;
|
||||
|
||||
// only full table is allowed ?
|
||||
if ( SumFreqs(freqs_L, NUM_L_SYMBOLS) != NUM_L_STATES
|
||||
|| SumFreqs(freqs_M, NUM_M_SYMBOLS) != NUM_M_STATES
|
||||
|| SumFreqs(freqs_D, NUM_D_SYMBOLS) != NUM_D_STATES
|
||||
|| SumFreqs(freqs_LIT, NUM_LIT_SYMBOLS) != NUM_LIT_STATES)
|
||||
return S_FALSE;
|
||||
|
||||
|
||||
const unsigned kPad = 16;
|
||||
|
||||
// ---------- Decode literals ----------
|
||||
|
||||
{
|
||||
_literals.AllocAtLeast(LITERALS_PER_BLOCK + 16);
|
||||
_buffer.AllocAtLeast(kPad + litPayloadSize);
|
||||
memset(_buffer, 0, kPad);
|
||||
|
||||
if (m_InStream.ReadBytes(_buffer + kPad, litPayloadSize) != litPayloadSize)
|
||||
return S_FALSE;
|
||||
|
||||
UInt32 lit_decoder[NUM_LIT_STATES];
|
||||
InitLitTable(freqs_LIT, lit_decoder);
|
||||
|
||||
const Byte *buf_start = _buffer + kPad;
|
||||
const Byte *buf_check = buf_start - 4;
|
||||
const Byte *buf = buf_start + litPayloadSize;
|
||||
CBitStream in;
|
||||
if (FseInStream_Init(&in, literal_bits, &buf) != 0)
|
||||
return S_FALSE;
|
||||
|
||||
Byte *lit = _literals;
|
||||
const Byte *lit_limit = lit + numLiterals;
|
||||
for (; lit < lit_limit; lit += 4)
|
||||
{
|
||||
FseInStream_FLUSH
|
||||
DECODE_LIT (lit[0], lit_state_0);
|
||||
DECODE_LIT (lit[1], lit_state_1);
|
||||
FseInStream_FLUSH
|
||||
DECODE_LIT (lit[2], lit_state_2);
|
||||
DECODE_LIT (lit[3], lit_state_3);
|
||||
}
|
||||
|
||||
if ((buf_start - buf) * 8 != (int)in.numBits)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
|
||||
// ---------- Decode LMD ----------
|
||||
|
||||
_buffer.AllocAtLeast(kPad + lmdPayloadSize);
|
||||
memset(_buffer, 0, kPad);
|
||||
if (m_InStream.ReadBytes(_buffer + kPad, lmdPayloadSize) != lmdPayloadSize)
|
||||
return S_FALSE;
|
||||
|
||||
CExtraEntry l_decoder[NUM_L_STATES];
|
||||
CExtraEntry m_decoder[NUM_M_STATES];
|
||||
CExtraEntry d_decoder[NUM_D_STATES];
|
||||
|
||||
InitExtraDecoderTable(NUM_L_STATES, NUM_L_SYMBOLS, freqs_L, k_L_extra, l_decoder);
|
||||
InitExtraDecoderTable(NUM_M_STATES, NUM_M_SYMBOLS, freqs_M, k_M_extra, m_decoder);
|
||||
InitExtraDecoderTable(NUM_D_STATES, NUM_D_SYMBOLS, freqs_D, k_D_extra, d_decoder);
|
||||
|
||||
const Byte *buf_start = _buffer + kPad;
|
||||
const Byte *buf_check = buf_start - 4;
|
||||
const Byte *buf = buf_start + lmdPayloadSize;
|
||||
CBitStream in;
|
||||
if (FseInStream_Init(&in, lmd_bits, &buf))
|
||||
return S_FALSE;
|
||||
|
||||
const Byte *lit = _literals;
|
||||
const Byte *lit_limit = lit + numLiterals;
|
||||
|
||||
UInt32 D = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (numMatches == 0)
|
||||
break;
|
||||
numMatches--;
|
||||
|
||||
FseInStream_FLUSH
|
||||
|
||||
unsigned L = (unsigned)FseDecodeExtra(&l_state, l_decoder, &in);
|
||||
|
||||
FseInStream_FLUSH
|
||||
|
||||
unsigned M = (unsigned)FseDecodeExtra(&m_state, m_decoder, &in);
|
||||
|
||||
FseInStream_FLUSH
|
||||
|
||||
{
|
||||
UInt32 new_D = FseDecodeExtra(&d_state, d_decoder, &in);
|
||||
if (new_D)
|
||||
D = new_D;
|
||||
}
|
||||
|
||||
if (L != 0)
|
||||
{
|
||||
if (L > (size_t)(lit_limit - lit))
|
||||
return S_FALSE;
|
||||
unsigned cur = L;
|
||||
if (cur > unpackSize)
|
||||
cur = (unsigned)unpackSize;
|
||||
m_OutWindowStream.PutBytes(lit, cur);
|
||||
unpackSize -= cur;
|
||||
lit += cur;
|
||||
if (cur != L)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (M != 0)
|
||||
{
|
||||
if (unpackSize == 0 || D == 0)
|
||||
return S_FALSE;
|
||||
unsigned cur = M;
|
||||
if (cur > unpackSize)
|
||||
cur = (unsigned)unpackSize;
|
||||
if (!m_OutWindowStream.CopyBlock(D - 1, cur))
|
||||
return S_FALSE;
|
||||
unpackSize -= cur;
|
||||
if (cur != M)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (unpackSize != 0)
|
||||
return S_FALSE;
|
||||
|
||||
// LZFSE encoder writes 8 additional zero bytes before LMD payload
|
||||
// We test it:
|
||||
if ((buf - buf_start) * 8 + in.numBits != 64)
|
||||
return S_FALSE;
|
||||
if (GetUi64(buf_start) != 0)
|
||||
return S_FALSE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
PRF(printf("\n\nLzfseDecoder %7u %7u\n", (unsigned)*outSize, (unsigned)*inSize));
|
||||
|
||||
const UInt32 kLzfseDictSize = 1 << 18;
|
||||
if (!m_OutWindowStream.Create(kLzfseDictSize))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!m_InStream.Create(1 << 18))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
m_OutWindowStream.SetStream(outStream);
|
||||
m_OutWindowStream.Init(false);
|
||||
m_InStream.SetStream(inStream);
|
||||
m_InStream.Init();
|
||||
|
||||
CCoderReleaser coderReleaser(this);
|
||||
|
||||
UInt64 prevOut = 0;
|
||||
UInt64 prevIn = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
const UInt64 pos = m_OutWindowStream.GetProcessedSize();
|
||||
const UInt64 packPos = m_InStream.GetProcessedSize();
|
||||
|
||||
if (progress && ((pos - prevOut) >= (1 << 22) || (packPos - prevIn) >= (1 << 22)))
|
||||
{
|
||||
RINOK(progress->SetRatioInfo(&packPos, &pos));
|
||||
prevIn = packPos;
|
||||
prevOut = pos;
|
||||
}
|
||||
|
||||
const UInt64 rem = *outSize - pos;
|
||||
UInt32 v;
|
||||
RINOK(GetUInt32(v))
|
||||
if ((v & 0xFFFFFF) != 0x787662) // bvx
|
||||
return S_FALSE;
|
||||
v >>= 24;
|
||||
|
||||
if (v == 0x24) // '$', end of stream
|
||||
break;
|
||||
|
||||
UInt32 unpackSize;
|
||||
RINOK(GetUInt32(unpackSize));
|
||||
|
||||
UInt32 cur = unpackSize;
|
||||
if (cur > rem)
|
||||
cur = (UInt32)rem;
|
||||
|
||||
unpackSize -= cur;
|
||||
|
||||
HRESULT res;
|
||||
if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2)
|
||||
res = DecodeLzfse(cur, (Byte)v);
|
||||
else if (v == 0x6E) // 'n'
|
||||
res = DecodeLzvn(cur);
|
||||
else if (v == 0x2D) // '-'
|
||||
res = DecodeUncompressed(cur);
|
||||
else
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (res != S_OK)
|
||||
return res;
|
||||
|
||||
if (unpackSize != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
coderReleaser.NeedFlush = false;
|
||||
HRESULT res = m_OutWindowStream.Flush();
|
||||
if (res == S_OK)
|
||||
if (*inSize != m_InStream.GetProcessedSize()
|
||||
|| *outSize != m_OutWindowStream.GetProcessedSize())
|
||||
res = S_FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
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 E_OUTOFMEMORY; }
|
||||
// catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,58 @@
|
||||
// LzfseDecoder.h
|
||||
|
||||
#ifndef __LZFSE_DECODER_H
|
||||
#define __LZFSE_DECODER_H
|
||||
|
||||
#include "../../Common/MyBuffer.h"
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
|
||||
#include "LzOutWindow.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzfse {
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzOutWindow m_OutWindowStream;
|
||||
CInBuffer m_InStream;
|
||||
CByteBuffer _literals;
|
||||
CByteBuffer _buffer;
|
||||
|
||||
class CCoderReleaser
|
||||
{
|
||||
CDecoder *m_Coder;
|
||||
public:
|
||||
bool NeedFlush;
|
||||
CCoderReleaser(CDecoder *coder): m_Coder(coder), NeedFlush(true) {}
|
||||
~CCoderReleaser()
|
||||
{
|
||||
if (NeedFlush)
|
||||
m_Coder->m_OutWindowStream.Flush();
|
||||
}
|
||||
};
|
||||
friend class CCoderReleaser;
|
||||
|
||||
HRESULT GetUInt32(UInt32 &val);
|
||||
|
||||
HRESULT DecodeUncompressed(UInt32 unpackSize);
|
||||
HRESULT DecodeLzvn(UInt32 unpackSize);
|
||||
HRESULT DecodeLzfse(UInt32 unpackSize, Byte version);
|
||||
|
||||
STDMETHOD(CodeReal)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize,
|
||||
const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,250 @@
|
||||
// LzhDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "LzhDecoder.h"
|
||||
|
||||
namespace NCompress{
|
||||
namespace NLzh {
|
||||
namespace NDecoder {
|
||||
|
||||
static const UInt32 kWindowSizeMin = 1 << 16;
|
||||
|
||||
static bool CheckCodeLens(const Byte *lens, unsigned num)
|
||||
{
|
||||
UInt32 sum = 0;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
{
|
||||
unsigned len = lens[i];
|
||||
if (len != 0)
|
||||
sum += ((UInt32)1 << (NUM_CODE_BITS - len));
|
||||
}
|
||||
return sum == ((UInt32)1 << NUM_CODE_BITS);
|
||||
}
|
||||
|
||||
bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec)
|
||||
{
|
||||
_symbolT = -1;
|
||||
|
||||
UInt32 n = _inBitStream.ReadBits(numBits);
|
||||
if (n == 0)
|
||||
{
|
||||
_symbolT = _inBitStream.ReadBits(numBits);
|
||||
return ((unsigned)_symbolT < num);
|
||||
}
|
||||
|
||||
if (n > num)
|
||||
return false;
|
||||
|
||||
{
|
||||
Byte lens[NPT];
|
||||
unsigned i;
|
||||
for (i = 0; i < NPT; i++)
|
||||
lens[i] = 0;
|
||||
|
||||
i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
UInt32 val = _inBitStream.GetValue(16);
|
||||
unsigned c = val >> 13;
|
||||
|
||||
if (c == 7)
|
||||
{
|
||||
UInt32 mask = 1 << 12;
|
||||
while (mask & val)
|
||||
{
|
||||
mask >>= 1;
|
||||
c++;
|
||||
}
|
||||
if (c > 16)
|
||||
return false;
|
||||
}
|
||||
|
||||
_inBitStream.MovePos(c < 7 ? 3 : c - 3);
|
||||
lens[i++] = (Byte)c;
|
||||
|
||||
if (i == (unsigned)spec)
|
||||
i += _inBitStream.ReadBits(2);
|
||||
}
|
||||
while (i < n);
|
||||
|
||||
if (!CheckCodeLens(lens, NPT))
|
||||
return false;
|
||||
return _decoderT.Build(lens);
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned NUM_C_BITS = 9;
|
||||
|
||||
bool CCoder::ReadC()
|
||||
{
|
||||
_symbolC = -1;
|
||||
|
||||
unsigned n = _inBitStream.ReadBits(NUM_C_BITS);
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
_symbolC = _inBitStream.ReadBits(NUM_C_BITS);
|
||||
return ((unsigned)_symbolC < NC);
|
||||
}
|
||||
|
||||
if (n > NC)
|
||||
return false;
|
||||
|
||||
{
|
||||
Byte lens[NC];
|
||||
|
||||
unsigned i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
UInt32 c = (unsigned)_symbolT;
|
||||
if (_symbolT < 0)
|
||||
c = _decoderT.Decode(&_inBitStream);
|
||||
|
||||
if (c <= 2)
|
||||
{
|
||||
if (c == 0)
|
||||
c = 1;
|
||||
else if (c == 1)
|
||||
c = _inBitStream.ReadBits(4) + 3;
|
||||
else
|
||||
c = _inBitStream.ReadBits(NUM_C_BITS) + 20;
|
||||
|
||||
if (i + c > n)
|
||||
return false;
|
||||
|
||||
do
|
||||
lens[i++] = 0;
|
||||
while (--c);
|
||||
}
|
||||
else
|
||||
lens[i++] = (Byte)(c - 2);
|
||||
}
|
||||
while (i < n);
|
||||
|
||||
while (i < NC)
|
||||
lens[i++] = 0;
|
||||
|
||||
if (!CheckCodeLens(lens, NC))
|
||||
return false;
|
||||
return _decoderC.Build(lens);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
|
||||
{
|
||||
unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5);
|
||||
|
||||
UInt32 blockSize = 0;
|
||||
|
||||
while (rem != 0)
|
||||
{
|
||||
if (blockSize == 0)
|
||||
{
|
||||
if (_inBitStream.ExtraBitsWereRead())
|
||||
return S_FALSE;
|
||||
|
||||
if (progress)
|
||||
{
|
||||
UInt64 packSize = _inBitStream.GetProcessedSize();
|
||||
UInt64 pos = _outWindow.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &pos));
|
||||
}
|
||||
|
||||
blockSize = _inBitStream.ReadBits(16);
|
||||
if (blockSize == 0)
|
||||
return S_FALSE;
|
||||
|
||||
if (!ReadTP(NT, 5, 3))
|
||||
return S_FALSE;
|
||||
if (!ReadC())
|
||||
return S_FALSE;
|
||||
if (!ReadTP(NP, pbit, -1))
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
blockSize--;
|
||||
|
||||
UInt32 number = (unsigned)_symbolC;
|
||||
if (_symbolC < 0)
|
||||
number = _decoderC.Decode(&_inBitStream);
|
||||
|
||||
if (number < 256)
|
||||
{
|
||||
_outWindow.PutByte((Byte)number);
|
||||
rem--;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 len = number - 256 + kMatchMinLen;
|
||||
|
||||
UInt32 dist = (unsigned)_symbolT;
|
||||
if (_symbolT < 0)
|
||||
dist = _decoderT.Decode(&_inBitStream);
|
||||
|
||||
if (dist > 1)
|
||||
{
|
||||
dist--;
|
||||
dist = ((UInt32)1 << dist) + _inBitStream.ReadBits((unsigned)dist);
|
||||
}
|
||||
|
||||
if (dist >= DictSize)
|
||||
return S_FALSE;
|
||||
|
||||
if (len > rem)
|
||||
len = (UInt32)rem;
|
||||
|
||||
if (!_outWindow.CopyBlock(dist, len))
|
||||
return S_FALSE;
|
||||
rem -= len;
|
||||
}
|
||||
}
|
||||
|
||||
if (FinishMode)
|
||||
{
|
||||
if (blockSize != 0)
|
||||
return S_FALSE;
|
||||
if (_inBitStream.ReadAlignBits() != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (_inBitStream.ExtraBitsWereRead())
|
||||
return S_FALSE;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!outSize)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (!_outWindow.Create(DictSize > kWindowSizeMin ? DictSize : kWindowSizeMin))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_inBitStream.Create(1 << 17))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
_outWindow.SetStream(outStream);
|
||||
_outWindow.Init(false);
|
||||
_inBitStream.SetStream(inStream);
|
||||
_inBitStream.Init();
|
||||
|
||||
CCoderReleaser coderReleaser(this);
|
||||
|
||||
RINOK(CodeReal(*outSize, progress));
|
||||
|
||||
coderReleaser.Disable();
|
||||
return _outWindow.Flush();
|
||||
}
|
||||
catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
}}}
|
||||
@@ -0,0 +1,74 @@
|
||||
// LzhDecoder.h
|
||||
|
||||
#ifndef __COMPRESS_LZH_DECODER_H
|
||||
#define __COMPRESS_LZH_DECODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
|
||||
#include "BitmDecoder.h"
|
||||
#include "HuffmanDecoder.h"
|
||||
#include "LzOutWindow.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzh {
|
||||
namespace NDecoder {
|
||||
|
||||
const unsigned kMatchMinLen = 3;
|
||||
const unsigned kMatchMaxLen = 256;
|
||||
const unsigned NC = (256 + kMatchMaxLen - kMatchMinLen + 1);
|
||||
const unsigned NUM_CODE_BITS = 16;
|
||||
const unsigned NUM_DIC_BITS_MAX = 25;
|
||||
const unsigned NT = (NUM_CODE_BITS + 3);
|
||||
const unsigned NP = (NUM_DIC_BITS_MAX + 1);
|
||||
const unsigned NPT = NP; // Max(NT, NP)
|
||||
|
||||
class CCoder:
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzOutWindow _outWindow;
|
||||
NBitm::CDecoder<CInBuffer> _inBitStream;
|
||||
|
||||
int _symbolT;
|
||||
int _symbolC;
|
||||
|
||||
NHuffman::CDecoder<NUM_CODE_BITS, NPT> _decoderT;
|
||||
NHuffman::CDecoder<NUM_CODE_BITS, NC> _decoderC;
|
||||
|
||||
class CCoderReleaser
|
||||
{
|
||||
CCoder *_coder;
|
||||
public:
|
||||
CCoderReleaser(CCoder *coder): _coder(coder) {}
|
||||
void Disable() { _coder = NULL; }
|
||||
~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); }
|
||||
};
|
||||
friend class CCoderReleaser;
|
||||
|
||||
bool ReadTP(unsigned num, unsigned numBits, int spec);
|
||||
bool ReadC();
|
||||
|
||||
HRESULT CodeReal(UInt64 outSize, ICompressProgressInfo *progress);
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
UInt32 DictSize;
|
||||
bool FinishMode;
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
void SetDictSize(unsigned dictSize) { DictSize = dictSize; }
|
||||
|
||||
CCoder(): DictSize(1 << 16), FinishMode(false) {}
|
||||
|
||||
UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); }
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,265 @@
|
||||
// Lzma2Decoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
// #include "../../../C/CpuTicks.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "Lzma2Decoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzma2 {
|
||||
|
||||
CDecoder::CDecoder():
|
||||
_dec(NULL)
|
||||
, _inProcessed(0)
|
||||
, _prop(0xFF)
|
||||
, _finishMode(false)
|
||||
, _inBufSize(1 << 20)
|
||||
, _outStep(1 << 20)
|
||||
#ifndef _7ZIP_ST
|
||||
, _tryMt(1)
|
||||
, _numThreads(1)
|
||||
, _memUsage((UInt64)(sizeof(size_t)) << 28)
|
||||
#endif
|
||||
{}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
if (_dec)
|
||||
Lzma2DecMt_Destroy(_dec);
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }
|
||||
STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
|
||||
{
|
||||
if (size != 1)
|
||||
return E_NOTIMPL;
|
||||
if (prop[0] > 40)
|
||||
return E_NOTIMPL;
|
||||
_prop = prop[0];
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
|
||||
{
|
||||
_finishMode = (finishMode != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
|
||||
static UInt64 Get_ExpectedBlockSize_From_Dict(UInt32 dictSize)
|
||||
{
|
||||
const UInt32 kMinSize = (UInt32)1 << 20;
|
||||
const UInt32 kMaxSize = (UInt32)1 << 28;
|
||||
UInt64 blockSize = (UInt64)dictSize << 2;
|
||||
if (blockSize < kMinSize) blockSize = kMinSize;
|
||||
if (blockSize > kMaxSize) blockSize = kMaxSize;
|
||||
if (blockSize < dictSize) blockSize = dictSize;
|
||||
blockSize += (kMinSize - 1);
|
||||
blockSize &= ~(UInt64)(kMinSize - 1);
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
#define LZMA2_DIC_SIZE_FROM_PROP_FULL(p) ((p) == 40 ? 0xFFFFFFFF : (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)))
|
||||
|
||||
#endif
|
||||
|
||||
#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \
|
||||
if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes;
|
||||
|
||||
#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
|
||||
if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
_inProcessed = 0;
|
||||
|
||||
if (!_dec)
|
||||
{
|
||||
_dec = Lzma2DecMt_Create(
|
||||
// &g_AlignedAlloc,
|
||||
&g_Alloc,
|
||||
&g_MidAlloc);
|
||||
if (!_dec)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
CLzma2DecMtProps props;
|
||||
Lzma2DecMtProps_Init(&props);
|
||||
|
||||
props.inBufSize_ST = _inBufSize;
|
||||
props.outStep_ST = _outStep;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
{
|
||||
props.numThreads = 1;
|
||||
UInt32 numThreads = _numThreads;
|
||||
|
||||
if (_tryMt && numThreads >= 1)
|
||||
{
|
||||
UInt64 useLimit = _memUsage;
|
||||
UInt32 dictSize = LZMA2_DIC_SIZE_FROM_PROP_FULL(_prop);
|
||||
UInt64 expectedBlockSize64 = Get_ExpectedBlockSize_From_Dict(dictSize);
|
||||
size_t expectedBlockSize = (size_t)expectedBlockSize64;
|
||||
size_t inBlockMax = expectedBlockSize + expectedBlockSize / 16;
|
||||
if (expectedBlockSize == expectedBlockSize64 && inBlockMax >= expectedBlockSize)
|
||||
{
|
||||
props.outBlockMax = expectedBlockSize;
|
||||
props.inBlockMax = inBlockMax;
|
||||
const size_t kOverheadSize = props.inBufSize_MT + (1 << 16);
|
||||
UInt64 okThreads = useLimit / (props.outBlockMax + props.inBlockMax + kOverheadSize);
|
||||
if (numThreads > okThreads)
|
||||
numThreads = (UInt32)okThreads;
|
||||
if (numThreads == 0)
|
||||
numThreads = 1;
|
||||
props.numThreads = numThreads;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
CSeqInStreamWrap inWrap;
|
||||
CSeqOutStreamWrap outWrap;
|
||||
CCompressProgressWrap progressWrap;
|
||||
|
||||
inWrap.Init(inStream);
|
||||
outWrap.Init(outStream);
|
||||
progressWrap.Init(progress);
|
||||
|
||||
SRes res;
|
||||
|
||||
UInt64 inProcessed = 0;
|
||||
int isMT = False;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
isMT = _tryMt;
|
||||
#endif
|
||||
|
||||
// UInt64 cpuTicks = GetCpuTicks();
|
||||
|
||||
res = Lzma2DecMt_Decode(_dec, _prop, &props,
|
||||
&outWrap.vt, outSize, _finishMode,
|
||||
&inWrap.vt,
|
||||
&inProcessed,
|
||||
&isMT,
|
||||
progress ? &progressWrap.vt : NULL);
|
||||
|
||||
/*
|
||||
cpuTicks = GetCpuTicks() - cpuTicks;
|
||||
printf("\n ticks = %10I64u\n", cpuTicks / 1000000);
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
/* we reset _tryMt, only if p->props.numThreads was changed */
|
||||
if (props.numThreads > 1)
|
||||
_tryMt = isMT;
|
||||
#endif
|
||||
|
||||
_inProcessed = inProcessed;
|
||||
|
||||
RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
|
||||
RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
|
||||
RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ)
|
||||
|
||||
if (res == SZ_OK && _finishMode)
|
||||
{
|
||||
if (inSize && *inSize != inProcessed)
|
||||
res = SZ_ERROR_DATA;
|
||||
if (outSize && *outSize != outWrap.Processed)
|
||||
res = SZ_ERROR_DATA;
|
||||
}
|
||||
|
||||
return SResToHRESULT(res);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
*value = _inProcessed;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
|
||||
STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads)
|
||||
{
|
||||
_numThreads = numThreads;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetMemLimit(UInt64 memUsage)
|
||||
{
|
||||
_memUsage = memUsage;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
|
||||
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
||||
{
|
||||
CLzma2DecMtProps props;
|
||||
Lzma2DecMtProps_Init(&props);
|
||||
props.inBufSize_ST = _inBufSize;
|
||||
props.outStep_ST = _outStep;
|
||||
|
||||
_inProcessed = 0;
|
||||
|
||||
if (!_dec)
|
||||
{
|
||||
_dec = Lzma2DecMt_Create(&g_AlignedAlloc, &g_MidAlloc);
|
||||
if (!_dec)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
_inWrap.Init(_inStream);
|
||||
|
||||
SRes res = Lzma2DecMt_Init(_dec, _prop, &props, outSize, _finishMode, &_inWrap.vt);
|
||||
|
||||
if (res != SZ_OK)
|
||||
return SResToHRESULT(res);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
|
||||
STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
|
||||
size_t size2 = size;
|
||||
UInt64 inProcessed = 0;
|
||||
|
||||
SRes res = Lzma2DecMt_Read(_dec, (Byte *)data, &size2, &inProcessed);
|
||||
|
||||
_inProcessed += inProcessed;
|
||||
if (processedSize)
|
||||
*processedSize = (UInt32)size2;
|
||||
if (res != SZ_OK)
|
||||
return SResToHRESULT(res);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Lzma2Decoder.h
|
||||
|
||||
#ifndef __LZMA2_DECODER_H
|
||||
#define __LZMA2_DECODER_H
|
||||
|
||||
#include "../../../C/Lzma2DecMt.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzma2 {
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetDecoderProperties2,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
public ICompressSetBufSize,
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
public ICompressSetInStream,
|
||||
public ICompressSetOutStreamSize,
|
||||
public ISequentialInStream,
|
||||
#endif
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
public ICompressSetCoderMt,
|
||||
public ICompressSetMemLimit,
|
||||
#endif
|
||||
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzma2DecMtHandle _dec;
|
||||
UInt64 _inProcessed;
|
||||
Byte _prop;
|
||||
int _finishMode;
|
||||
UInt32 _inBufSize;
|
||||
UInt32 _outStep;
|
||||
|
||||
public:
|
||||
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
|
||||
MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
|
||||
#endif
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetMemLimit)
|
||||
#endif
|
||||
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
|
||||
STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
private:
|
||||
int _tryMt;
|
||||
UInt32 _numThreads;
|
||||
UInt64 _memUsage;
|
||||
public:
|
||||
STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
|
||||
STDMETHOD(SetMemLimit)(UInt64 memUsage);
|
||||
#endif
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
private:
|
||||
CMyComPtr<ISequentialInStream> _inStream;
|
||||
CSeqInStreamWrap _inWrap;
|
||||
public:
|
||||
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
|
||||
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
|
||||
STDMETHOD(ReleaseInStream)();
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
#endif
|
||||
|
||||
CDecoder();
|
||||
virtual ~CDecoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,122 @@
|
||||
// Lzma2Encoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "Lzma2Encoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
|
||||
namespace NLzma {
|
||||
|
||||
HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep);
|
||||
|
||||
}
|
||||
|
||||
namespace NLzma2 {
|
||||
|
||||
CEncoder::CEncoder()
|
||||
{
|
||||
_encoder = NULL;
|
||||
_encoder = Lzma2Enc_Create(&g_AlignedAlloc, &g_BigAlloc);
|
||||
if (!_encoder)
|
||||
throw 1;
|
||||
}
|
||||
|
||||
CEncoder::~CEncoder()
|
||||
{
|
||||
if (_encoder)
|
||||
Lzma2Enc_Destroy(_encoder);
|
||||
}
|
||||
|
||||
|
||||
HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props)
|
||||
{
|
||||
switch (propID)
|
||||
{
|
||||
case NCoderPropID::kBlockSize:
|
||||
{
|
||||
if (prop.vt == VT_UI4)
|
||||
lzma2Props.blockSize = prop.ulVal;
|
||||
else if (prop.vt == VT_UI8)
|
||||
lzma2Props.blockSize = prop.uhVal.QuadPart;
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
break;
|
||||
}
|
||||
case NCoderPropID::kNumThreads:
|
||||
if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.numTotalThreads = (int)(prop.ulVal); break;
|
||||
default:
|
||||
RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
|
||||
const PROPVARIANT *coderProps, UInt32 numProps)
|
||||
{
|
||||
CLzma2EncProps lzma2Props;
|
||||
Lzma2EncProps_Init(&lzma2Props);
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props));
|
||||
}
|
||||
return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props));
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
|
||||
const PROPVARIANT *coderProps, UInt32 numProps)
|
||||
{
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = coderProps[i];
|
||||
PROPID propID = propIDs[i];
|
||||
if (propID == NCoderPropID::kExpectedDataSize)
|
||||
if (prop.vt == VT_UI8)
|
||||
Lzma2Enc_SetDataSize(_encoder, prop.uhVal.QuadPart);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
|
||||
{
|
||||
Byte prop = Lzma2Enc_WriteProperties(_encoder);
|
||||
return WriteStream(outStream, &prop, 1);
|
||||
}
|
||||
|
||||
|
||||
#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
|
||||
if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
|
||||
|
||||
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
CSeqInStreamWrap inWrap;
|
||||
CSeqOutStreamWrap outWrap;
|
||||
CCompressProgressWrap progressWrap;
|
||||
|
||||
inWrap.Init(inStream);
|
||||
outWrap.Init(outStream);
|
||||
progressWrap.Init(progress);
|
||||
|
||||
SRes res = Lzma2Enc_Encode2(_encoder,
|
||||
&outWrap.vt, NULL, NULL,
|
||||
&inWrap.vt, NULL, 0,
|
||||
progress ? &progressWrap.vt : NULL);
|
||||
|
||||
RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
|
||||
RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
|
||||
RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
|
||||
|
||||
return SResToHRESULT(res);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Lzma2Encoder.h
|
||||
|
||||
#ifndef __LZMA2_ENCODER_H
|
||||
#define __LZMA2_ENCODER_H
|
||||
|
||||
#include "../../../C/Lzma2Enc.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzma2 {
|
||||
|
||||
class CEncoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
public ICompressWriteCoderProperties,
|
||||
public ICompressSetCoderPropertiesOpt,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzma2EncHandle _encoder;
|
||||
public:
|
||||
MY_UNKNOWN_IMP4(
|
||||
ICompressCoder,
|
||||
ICompressSetCoderProperties,
|
||||
ICompressWriteCoderProperties,
|
||||
ICompressSetCoderPropertiesOpt)
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
|
||||
STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
|
||||
CEncoder();
|
||||
virtual ~CEncoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// Lzma2Register.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "Lzma2Decoder.h"
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
#include "Lzma2Encoder.h"
|
||||
#endif
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzma2 {
|
||||
|
||||
REGISTER_CODEC_E(LZMA2,
|
||||
CDecoder(),
|
||||
CEncoder(),
|
||||
0x21,
|
||||
"LZMA2")
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,343 @@
|
||||
// LzmaDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "LzmaDecoder.h"
|
||||
|
||||
static HRESULT SResToHRESULT(SRes res)
|
||||
{
|
||||
switch (res)
|
||||
{
|
||||
case SZ_OK: return S_OK;
|
||||
case SZ_ERROR_MEM: return E_OUTOFMEMORY;
|
||||
case SZ_ERROR_PARAM: return E_INVALIDARG;
|
||||
case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
|
||||
case SZ_ERROR_DATA: return S_FALSE;
|
||||
}
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzma {
|
||||
|
||||
CDecoder::CDecoder():
|
||||
_inBuf(NULL),
|
||||
_lzmaStatus(LZMA_STATUS_NOT_SPECIFIED),
|
||||
FinishStream(false),
|
||||
_propsWereSet(false),
|
||||
_outSizeDefined(false),
|
||||
_outStep(1 << 20),
|
||||
_inBufSize(0),
|
||||
_inBufSizeNew(1 << 20)
|
||||
{
|
||||
_inProcessed = 0;
|
||||
_inPos = _inLim = 0;
|
||||
|
||||
/*
|
||||
AlignOffsetAlloc_CreateVTable(&_alloc);
|
||||
_alloc.numAlignBits = 7;
|
||||
_alloc.offset = 0;
|
||||
*/
|
||||
LzmaDec_Construct(&_state);
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
LzmaDec_Free(&_state, &g_AlignedAlloc); // &_alloc.vt
|
||||
MyFree(_inBuf);
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; }
|
||||
STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }
|
||||
|
||||
HRESULT CDecoder::CreateInputBuffer()
|
||||
{
|
||||
if (!_inBuf || _inBufSizeNew != _inBufSize)
|
||||
{
|
||||
MyFree(_inBuf);
|
||||
_inBufSize = 0;
|
||||
_inBuf = (Byte *)MyAlloc(_inBufSizeNew);
|
||||
if (!_inBuf)
|
||||
return E_OUTOFMEMORY;
|
||||
_inBufSize = _inBufSizeNew;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
|
||||
{
|
||||
RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_AlignedAlloc))) // &_alloc.vt
|
||||
_propsWereSet = true;
|
||||
return CreateInputBuffer();
|
||||
}
|
||||
|
||||
|
||||
void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)
|
||||
{
|
||||
_outSizeDefined = (outSize != NULL);
|
||||
_outSize = 0;
|
||||
if (_outSizeDefined)
|
||||
_outSize = *outSize;
|
||||
_outProcessed = 0;
|
||||
_lzmaStatus = LZMA_STATUS_NOT_SPECIFIED;
|
||||
|
||||
LzmaDec_Init(&_state);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
||||
{
|
||||
_inProcessed = 0;
|
||||
_inPos = _inLim = 0;
|
||||
SetOutStreamSizeResume(outSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
|
||||
{
|
||||
FinishStream = (finishMode != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
*value = _inProcessed;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_inBuf || !_propsWereSet)
|
||||
return S_FALSE;
|
||||
|
||||
const UInt64 startInProgress = _inProcessed;
|
||||
SizeT wrPos = _state.dicPos;
|
||||
HRESULT readRes = S_OK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (_inPos == _inLim && readRes == S_OK)
|
||||
{
|
||||
_inPos = _inLim = 0;
|
||||
readRes = inStream->Read(_inBuf, _inBufSize, &_inLim);
|
||||
}
|
||||
|
||||
const SizeT dicPos = _state.dicPos;
|
||||
SizeT size;
|
||||
{
|
||||
SizeT next = _state.dicBufSize;
|
||||
if (next - wrPos > _outStep)
|
||||
next = wrPos + _outStep;
|
||||
size = next - dicPos;
|
||||
}
|
||||
|
||||
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
|
||||
if (_outSizeDefined)
|
||||
{
|
||||
const UInt64 rem = _outSize - _outProcessed;
|
||||
if (size >= rem)
|
||||
{
|
||||
size = (SizeT)rem;
|
||||
if (FinishStream)
|
||||
finishMode = LZMA_FINISH_END;
|
||||
}
|
||||
}
|
||||
|
||||
SizeT inProcessed = _inLim - _inPos;
|
||||
ELzmaStatus status;
|
||||
|
||||
SRes res = LzmaDec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status);
|
||||
|
||||
_lzmaStatus = status;
|
||||
_inPos += (UInt32)inProcessed;
|
||||
_inProcessed += inProcessed;
|
||||
const SizeT outProcessed = _state.dicPos - dicPos;
|
||||
_outProcessed += outProcessed;
|
||||
|
||||
// we check for LZMA_STATUS_NEEDS_MORE_INPUT to allow RangeCoder initialization, if (_outSizeDefined && _outSize == 0)
|
||||
bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);
|
||||
|
||||
bool needStop = (res != 0
|
||||
|| (inProcessed == 0 && outProcessed == 0)
|
||||
|| status == LZMA_STATUS_FINISHED_WITH_MARK
|
||||
|| (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT));
|
||||
|
||||
if (needStop || outProcessed >= size)
|
||||
{
|
||||
HRESULT res2 = WriteStream(outStream, _state.dic + wrPos, _state.dicPos - wrPos);
|
||||
|
||||
if (_state.dicPos == _state.dicBufSize)
|
||||
_state.dicPos = 0;
|
||||
wrPos = _state.dicPos;
|
||||
|
||||
RINOK(res2);
|
||||
|
||||
if (needStop)
|
||||
{
|
||||
if (res != 0)
|
||||
return S_FALSE;
|
||||
|
||||
if (status == LZMA_STATUS_FINISHED_WITH_MARK)
|
||||
{
|
||||
if (FinishStream)
|
||||
if (_outSizeDefined && _outSize != _outProcessed)
|
||||
return S_FALSE;
|
||||
return readRes;
|
||||
}
|
||||
|
||||
if (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||
if (!FinishStream || status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
|
||||
return readRes;
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
{
|
||||
const UInt64 inSize = _inProcessed - startInProgress;
|
||||
RINOK(progress->SetRatioInfo(&inSize, &_outProcessed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_inBuf)
|
||||
return E_INVALIDARG;
|
||||
SetOutStreamSize(outSize);
|
||||
HRESULT res = CodeSpec(inStream, outStream, progress);
|
||||
if (res == S_OK)
|
||||
if (FinishStream && inSize && *inSize != _inProcessed)
|
||||
res = S_FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
|
||||
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
|
||||
STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
|
||||
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
|
||||
if (_outSizeDefined)
|
||||
{
|
||||
const UInt64 rem = _outSize - _outProcessed;
|
||||
if (size >= rem)
|
||||
{
|
||||
size = (UInt32)rem;
|
||||
if (FinishStream)
|
||||
finishMode = LZMA_FINISH_END;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT readRes = S_OK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (_inPos == _inLim && readRes == S_OK)
|
||||
{
|
||||
_inPos = _inLim = 0;
|
||||
readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
|
||||
}
|
||||
|
||||
SizeT inProcessed = _inLim - _inPos;
|
||||
SizeT outProcessed = size;
|
||||
ELzmaStatus status;
|
||||
|
||||
SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
|
||||
_inBuf + _inPos, &inProcessed, finishMode, &status);
|
||||
|
||||
_lzmaStatus = status;
|
||||
_inPos += (UInt32)inProcessed;
|
||||
_inProcessed += inProcessed;
|
||||
_outProcessed += outProcessed;
|
||||
size -= (UInt32)outProcessed;
|
||||
data = (Byte *)data + outProcessed;
|
||||
if (processedSize)
|
||||
*processedSize += (UInt32)outProcessed;
|
||||
|
||||
if (res != 0)
|
||||
return S_FALSE;
|
||||
|
||||
/*
|
||||
if (status == LZMA_STATUS_FINISHED_WITH_MARK)
|
||||
return readRes;
|
||||
|
||||
if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)
|
||||
{
|
||||
if (FinishStream
|
||||
&& _outSizeDefined && _outProcessed >= _outSize
|
||||
&& status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
|
||||
return S_FALSE;
|
||||
return readRes;
|
||||
}
|
||||
*/
|
||||
|
||||
if (inProcessed == 0 && outProcessed == 0)
|
||||
return readRes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
SetOutStreamSizeResume(outSize);
|
||||
return CodeSpec(_inStream, outStream, progress);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
RINOK(CreateInputBuffer());
|
||||
|
||||
if (processedSize)
|
||||
*processedSize = 0;
|
||||
|
||||
HRESULT readRes = S_OK;
|
||||
|
||||
while (size != 0)
|
||||
{
|
||||
if (_inPos == _inLim)
|
||||
{
|
||||
_inPos = _inLim = 0;
|
||||
if (readRes == S_OK)
|
||||
readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
|
||||
if (_inLim == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
UInt32 cur = _inLim - _inPos;
|
||||
if (cur > size)
|
||||
cur = size;
|
||||
memcpy(data, _inBuf + _inPos, cur);
|
||||
_inPos += cur;
|
||||
_inProcessed += cur;
|
||||
size -= cur;
|
||||
data = (Byte *)data + cur;
|
||||
if (processedSize)
|
||||
*processedSize += cur;
|
||||
}
|
||||
|
||||
return readRes;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,113 @@
|
||||
// LzmaDecoder.h
|
||||
|
||||
#ifndef __LZMA_DECODER_H
|
||||
#define __LZMA_DECODER_H
|
||||
|
||||
// #include "../../../C/Alloc.h"
|
||||
#include "../../../C/LzmaDec.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzma {
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetDecoderProperties2,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
public ICompressSetBufSize,
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
public ICompressSetInStream,
|
||||
public ICompressSetOutStreamSize,
|
||||
public ISequentialInStream,
|
||||
#endif
|
||||
public CMyUnknownImp
|
||||
{
|
||||
Byte *_inBuf;
|
||||
UInt32 _inPos;
|
||||
UInt32 _inLim;
|
||||
|
||||
ELzmaStatus _lzmaStatus;
|
||||
|
||||
public:
|
||||
bool FinishStream; // set it before decoding, if you need to decode full LZMA stream
|
||||
|
||||
private:
|
||||
bool _propsWereSet;
|
||||
bool _outSizeDefined;
|
||||
UInt64 _outSize;
|
||||
UInt64 _inProcessed;
|
||||
UInt64 _outProcessed;
|
||||
|
||||
UInt32 _outStep;
|
||||
UInt32 _inBufSize;
|
||||
UInt32 _inBufSizeNew;
|
||||
|
||||
// CAlignOffsetAlloc _alloc;
|
||||
|
||||
CLzmaDec _state;
|
||||
|
||||
HRESULT CreateInputBuffer();
|
||||
HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
|
||||
void SetOutStreamSizeResume(const UInt64 *outSize);
|
||||
|
||||
public:
|
||||
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
|
||||
MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
|
||||
#endif
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
|
||||
STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
|
||||
STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
|
||||
private:
|
||||
CMyComPtr<ISequentialInStream> _inStream;
|
||||
public:
|
||||
|
||||
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
|
||||
STDMETHOD(ReleaseInStream)();
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize);
|
||||
|
||||
#endif
|
||||
|
||||
UInt64 GetInputProcessedSize() const { return _inProcessed; }
|
||||
|
||||
CDecoder();
|
||||
virtual ~CDecoder();
|
||||
|
||||
UInt64 GetOutputProcessedSize() const { return _outProcessed; }
|
||||
|
||||
bool NeedsMoreInput() const { return _lzmaStatus == LZMA_STATUS_NEEDS_MORE_INPUT; }
|
||||
|
||||
bool CheckFinishStatus(bool withEndMark) const
|
||||
{
|
||||
return _lzmaStatus == (withEndMark ?
|
||||
LZMA_STATUS_FINISHED_WITH_MARK :
|
||||
LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK);
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,182 @@
|
||||
// LzmaEncoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "LzmaEncoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzma {
|
||||
|
||||
CEncoder::CEncoder()
|
||||
{
|
||||
_encoder = NULL;
|
||||
_encoder = LzmaEnc_Create(&g_AlignedAlloc);
|
||||
if (!_encoder)
|
||||
throw 1;
|
||||
}
|
||||
|
||||
CEncoder::~CEncoder()
|
||||
{
|
||||
if (_encoder)
|
||||
LzmaEnc_Destroy(_encoder, &g_AlignedAlloc, &g_BigAlloc);
|
||||
}
|
||||
|
||||
static inline wchar_t GetUpperChar(wchar_t c)
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
c -= 0x20;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
|
||||
{
|
||||
wchar_t c = GetUpperChar(*s++);
|
||||
if (c == L'H')
|
||||
{
|
||||
if (GetUpperChar(*s++) != L'C')
|
||||
return 0;
|
||||
int numHashBytesLoc = (int)(*s++ - L'0');
|
||||
if (numHashBytesLoc < 4 || numHashBytesLoc > 4)
|
||||
return 0;
|
||||
if (*s != 0)
|
||||
return 0;
|
||||
*btMode = 0;
|
||||
*numHashBytes = numHashBytesLoc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (c != L'B')
|
||||
return 0;
|
||||
if (GetUpperChar(*s++) != L'T')
|
||||
return 0;
|
||||
int numHashBytesLoc = (int)(*s++ - L'0');
|
||||
if (numHashBytesLoc < 2 || numHashBytesLoc > 4)
|
||||
return 0;
|
||||
if (*s != 0)
|
||||
return 0;
|
||||
*btMode = 1;
|
||||
*numHashBytes = numHashBytesLoc;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break;
|
||||
|
||||
HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
|
||||
{
|
||||
if (propID == NCoderPropID::kMatchFinder)
|
||||
{
|
||||
if (prop.vt != VT_BSTR)
|
||||
return E_INVALIDARG;
|
||||
return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG;
|
||||
}
|
||||
|
||||
if (propID > NCoderPropID::kReduceSize)
|
||||
return S_OK;
|
||||
|
||||
if (propID == NCoderPropID::kReduceSize)
|
||||
{
|
||||
if (prop.vt == VT_UI8)
|
||||
ep.reduceSize = prop.uhVal.QuadPart;
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
UInt32 v = prop.ulVal;
|
||||
switch (propID)
|
||||
{
|
||||
case NCoderPropID::kDefaultProp: if (v > 31) return E_INVALIDARG; ep.dictSize = (UInt32)1 << (unsigned)v; break;
|
||||
SET_PROP_32(kLevel, level)
|
||||
SET_PROP_32(kNumFastBytes, fb)
|
||||
SET_PROP_32(kMatchFinderCycles, mc)
|
||||
SET_PROP_32(kAlgorithm, algo)
|
||||
SET_PROP_32(kDictionarySize, dictSize)
|
||||
SET_PROP_32(kPosStateBits, pb)
|
||||
SET_PROP_32(kLitPosBits, lp)
|
||||
SET_PROP_32(kLitContextBits, lc)
|
||||
SET_PROP_32(kNumThreads, numThreads)
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
|
||||
const PROPVARIANT *coderProps, UInt32 numProps)
|
||||
{
|
||||
CLzmaEncProps props;
|
||||
LzmaEncProps_Init(&props);
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = coderProps[i];
|
||||
PROPID propID = propIDs[i];
|
||||
switch (propID)
|
||||
{
|
||||
case NCoderPropID::kEndMarker:
|
||||
if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal != VARIANT_FALSE); break;
|
||||
default:
|
||||
RINOK(SetLzmaProp(propID, prop, props));
|
||||
}
|
||||
}
|
||||
return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
|
||||
const PROPVARIANT *coderProps, UInt32 numProps)
|
||||
{
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = coderProps[i];
|
||||
PROPID propID = propIDs[i];
|
||||
if (propID == NCoderPropID::kExpectedDataSize)
|
||||
if (prop.vt == VT_UI8)
|
||||
LzmaEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
|
||||
{
|
||||
Byte props[LZMA_PROPS_SIZE];
|
||||
size_t size = LZMA_PROPS_SIZE;
|
||||
RINOK(LzmaEnc_WriteProperties(_encoder, props, &size));
|
||||
return WriteStream(outStream, props, size);
|
||||
}
|
||||
|
||||
|
||||
#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
|
||||
if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
|
||||
|
||||
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
CSeqInStreamWrap inWrap;
|
||||
CSeqOutStreamWrap outWrap;
|
||||
CCompressProgressWrap progressWrap;
|
||||
|
||||
inWrap.Init(inStream);
|
||||
outWrap.Init(outStream);
|
||||
progressWrap.Init(progress);
|
||||
|
||||
SRes res = LzmaEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt,
|
||||
progress ? &progressWrap.vt : NULL, &g_AlignedAlloc, &g_BigAlloc);
|
||||
|
||||
_inputProcessed = inWrap.Processed;
|
||||
|
||||
RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
|
||||
RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
|
||||
RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
|
||||
|
||||
return SResToHRESULT(res);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,46 @@
|
||||
// LzmaEncoder.h
|
||||
|
||||
#ifndef __LZMA_ENCODER_H
|
||||
#define __LZMA_ENCODER_H
|
||||
|
||||
#include "../../../C/LzmaEnc.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzma {
|
||||
|
||||
class CEncoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
public ICompressWriteCoderProperties,
|
||||
public ICompressSetCoderPropertiesOpt,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzmaEncHandle _encoder;
|
||||
UInt64 _inputProcessed;
|
||||
public:
|
||||
MY_UNKNOWN_IMP4(
|
||||
ICompressCoder,
|
||||
ICompressSetCoderProperties,
|
||||
ICompressWriteCoderProperties,
|
||||
ICompressSetCoderPropertiesOpt)
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
|
||||
STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
|
||||
CEncoder();
|
||||
virtual ~CEncoder();
|
||||
|
||||
UInt64 GetInputProcessedSize() const { return _inputProcessed; }
|
||||
bool IsWriteEndMark() const { return LzmaEnc_IsWriteEndMark(_encoder) != 0; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// LzmaRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "LzmaDecoder.h"
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
#include "LzmaEncoder.h"
|
||||
#endif
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzma {
|
||||
|
||||
REGISTER_CODEC_E(LZMA,
|
||||
CDecoder(),
|
||||
CEncoder(),
|
||||
0x30101,
|
||||
"LZMA")
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,576 @@
|
||||
// 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_t)size + kSave];
|
||||
data[(size_t)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_t)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);
|
||||
|
||||
{
|
||||
{
|
||||
{
|
||||
for (unsigned i = 0 ; i < k_NumReps + 1; i++)
|
||||
_reps[i] = i + 1;
|
||||
}
|
||||
|
||||
{
|
||||
for (unsigned 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;
|
||||
|
||||
size_t span = (size_t)1 << power;
|
||||
if ((UInt64)dist + span > _pos)
|
||||
return S_FALSE;
|
||||
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;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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
|
||||
@@ -0,0 +1,57 @@
|
||||
// Lzx.h
|
||||
|
||||
#ifndef __COMPRESS_LZX_H
|
||||
#define __COMPRESS_LZX_H
|
||||
|
||||
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 unsigned kNumReps = 3;
|
||||
|
||||
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 unsigned kAlignTableSize = 1 << kNumAlignBits;
|
||||
|
||||
const unsigned kNumPosSlots = 50;
|
||||
const unsigned kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
|
||||
|
||||
const unsigned kMainTableSize = 256 + kNumPosLenSlots;
|
||||
const unsigned kLevelTableSize = 20;
|
||||
const unsigned kMaxTableSize = kMainTableSize;
|
||||
|
||||
const unsigned kNumLevelBits = 4;
|
||||
|
||||
const unsigned kLevelSym_Zero1 = 17;
|
||||
const unsigned kLevelSym_Zero2 = 18;
|
||||
const unsigned kLevelSym_Same = 19;
|
||||
|
||||
const unsigned kLevelSym_Zero1_Start = 4;
|
||||
const unsigned kLevelSym_Zero1_NumBits = 4;
|
||||
|
||||
const unsigned kLevelSym_Zero2_Start = kLevelSym_Zero1_Start + (1 << kLevelSym_Zero1_NumBits);
|
||||
const unsigned kLevelSym_Zero2_NumBits = 5;
|
||||
|
||||
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 unsigned kNumPowerPosSlots = 38;
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -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_t)size + 4];
|
||||
data[(size_t)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_t)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;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,246 @@
|
||||
// LzxDecoder.h
|
||||
|
||||
#ifndef __LZX_DECODER_H
|
||||
#define __LZX_DECODER_H
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "HuffmanDecoder.h"
|
||||
#include "Lzx.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzx {
|
||||
|
||||
class CBitDecoder
|
||||
{
|
||||
unsigned _bitPos;
|
||||
UInt32 _value;
|
||||
const Byte *_buf;
|
||||
const Byte *_bufLim;
|
||||
UInt32 _extraSize;
|
||||
public:
|
||||
|
||||
void Init(const Byte *data, size_t size)
|
||||
{
|
||||
_buf = data;
|
||||
_bufLim = data + size - 1;
|
||||
_bitPos = 0;
|
||||
_extraSize = 0;
|
||||
}
|
||||
|
||||
size_t GetRem() const { return _bufLim + 1 - _buf; }
|
||||
bool WasExtraReadError_Fast() const { return _extraSize > 4; }
|
||||
|
||||
bool WasFinishedOK() const
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1);
|
||||
}
|
||||
|
||||
void MovePos(unsigned numBits)
|
||||
{
|
||||
_bitPos -= numBits;
|
||||
NormalizeSmall();
|
||||
}
|
||||
|
||||
UInt32 ReadBitsSmall(unsigned numBits)
|
||||
{
|
||||
_bitPos -= numBits;
|
||||
UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
|
||||
NormalizeSmall();
|
||||
return val;
|
||||
}
|
||||
|
||||
UInt32 ReadBitsBig(unsigned numBits)
|
||||
{
|
||||
_bitPos -= numBits;
|
||||
UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
|
||||
NormalizeBig();
|
||||
return val;
|
||||
}
|
||||
|
||||
bool PrepareUncompressed()
|
||||
{
|
||||
if (_extraSize != 0)
|
||||
return false;
|
||||
unsigned numBits = _bitPos - 16;
|
||||
if (((_value >> 16) & (((UInt32)1 << numBits) - 1)) != 0)
|
||||
return false;
|
||||
_buf -= 2;
|
||||
_bitPos = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
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 IUnknown,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CBitDecoder _bitStream;
|
||||
Byte *_win;
|
||||
UInt32 _pos;
|
||||
UInt32 _winSize;
|
||||
|
||||
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 *levels, unsigned numSymbols);
|
||||
bool ReadTables();
|
||||
|
||||
HRESULT CodeSpec(UInt32 size);
|
||||
HRESULT SetParams2(unsigned numDictBits);
|
||||
public:
|
||||
CDecoder(bool wimMode = false);
|
||||
~CDecoder();
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
HRESULT SetExternalWindow(Byte *win, unsigned numDictBits)
|
||||
{
|
||||
NeedAlloc = false;
|
||||
_win = win;
|
||||
_winSize = (UInt32)1 << numDictBits;
|
||||
return SetParams2(numDictBits);
|
||||
}
|
||||
|
||||
void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
|
||||
|
||||
HRESULT SetParams_and_Alloc(unsigned numDictBits);
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,212 @@
|
||||
// Mtf8.h
|
||||
|
||||
#ifndef __COMPRESS_MTF8_H
|
||||
#define __COMPRESS_MTF8_H
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
namespace NCompress {
|
||||
|
||||
struct CMtf8Encoder
|
||||
{
|
||||
Byte Buf[256];
|
||||
|
||||
unsigned FindAndMove(Byte v) throw()
|
||||
{
|
||||
size_t pos;
|
||||
for (pos = 0; Buf[pos] != v; pos++);
|
||||
unsigned resPos = (unsigned)pos;
|
||||
for (; pos >= 8; pos -= 8)
|
||||
{
|
||||
Buf[pos] = Buf[pos - 1];
|
||||
Buf[pos - 1] = Buf[pos - 2];
|
||||
Buf[pos - 2] = Buf[pos - 3];
|
||||
Buf[pos - 3] = Buf[pos - 4];
|
||||
Buf[pos - 4] = Buf[pos - 5];
|
||||
Buf[pos - 5] = Buf[pos - 6];
|
||||
Buf[pos - 6] = Buf[pos - 7];
|
||||
Buf[pos - 7] = Buf[pos - 8];
|
||||
}
|
||||
for (; pos != 0; pos--)
|
||||
Buf[pos] = Buf[pos - 1];
|
||||
Buf[0] = v;
|
||||
return resPos;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
struct CMtf8Decoder
|
||||
{
|
||||
Byte Buf[256];
|
||||
|
||||
void StartInit() { memset(Buf, 0, sizeof(Buf)); }
|
||||
void Add(unsigned pos, Byte val) { Buf[pos] = val; }
|
||||
Byte GetHead() const { return Buf[0]; }
|
||||
Byte GetAndMove(unsigned pos)
|
||||
{
|
||||
Byte res = Buf[pos];
|
||||
for (; pos >= 8; pos -= 8)
|
||||
{
|
||||
Buf[pos] = Buf[pos - 1];
|
||||
Buf[pos - 1] = Buf[pos - 2];
|
||||
Buf[pos - 2] = Buf[pos - 3];
|
||||
Buf[pos - 3] = Buf[pos - 4];
|
||||
Buf[pos - 4] = Buf[pos - 5];
|
||||
Buf[pos - 5] = Buf[pos - 6];
|
||||
Buf[pos - 6] = Buf[pos - 7];
|
||||
Buf[pos - 7] = Buf[pos - 8];
|
||||
}
|
||||
for (; pos > 0; pos--)
|
||||
Buf[pos] = Buf[pos - 1];
|
||||
Buf[0] = res;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
#ifdef MY_CPU_64BIT
|
||||
typedef UInt64 CMtfVar;
|
||||
#define MTF_MOVS 3
|
||||
#else
|
||||
typedef UInt32 CMtfVar;
|
||||
#define MTF_MOVS 2
|
||||
#endif
|
||||
|
||||
#define MTF_MASK ((1 << MTF_MOVS) - 1)
|
||||
|
||||
|
||||
struct CMtf8Decoder
|
||||
{
|
||||
CMtfVar Buf[256 >> MTF_MOVS];
|
||||
|
||||
void StartInit() { memset(Buf, 0, sizeof(Buf)); }
|
||||
void Add(unsigned pos, Byte val) { Buf[pos >> MTF_MOVS] |= ((CMtfVar)val << ((pos & MTF_MASK) << 3)); }
|
||||
Byte GetHead() const { return (Byte)Buf[0]; }
|
||||
|
||||
MY_FORCE_INLINE
|
||||
Byte GetAndMove(unsigned pos) throw()
|
||||
{
|
||||
UInt32 lim = ((UInt32)pos >> MTF_MOVS);
|
||||
pos = (pos & MTF_MASK) << 3;
|
||||
CMtfVar prev = (Buf[lim] >> pos) & 0xFF;
|
||||
|
||||
UInt32 i = 0;
|
||||
|
||||
|
||||
/*
|
||||
if ((lim & 1) != 0)
|
||||
{
|
||||
CMtfVar next = Buf[0];
|
||||
Buf[0] = (next << 8) | prev;
|
||||
prev = (next >> (MTF_MASK << 3));
|
||||
i = 1;
|
||||
lim -= 1;
|
||||
}
|
||||
for (; i < lim; i += 2)
|
||||
{
|
||||
CMtfVar n0 = Buf[i];
|
||||
CMtfVar n1 = Buf[i + 1];
|
||||
Buf[i ] = (n0 << 8) | prev;
|
||||
Buf[i + 1] = (n1 << 8) | (n0 >> (MTF_MASK << 3));
|
||||
prev = (n1 >> (MTF_MASK << 3));
|
||||
}
|
||||
*/
|
||||
|
||||
for (; i < lim; i++)
|
||||
{
|
||||
CMtfVar n0 = Buf[i];
|
||||
Buf[i ] = (n0 << 8) | prev;
|
||||
prev = (n0 >> (MTF_MASK << 3));
|
||||
}
|
||||
|
||||
|
||||
CMtfVar next = Buf[i];
|
||||
CMtfVar mask = (((CMtfVar)0x100 << pos) - 1);
|
||||
Buf[i] = (next & ~mask) | (((next << 8) | prev) & mask);
|
||||
return (Byte)Buf[0];
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
const int kSmallSize = 64;
|
||||
class CMtf8Decoder
|
||||
{
|
||||
Byte SmallBuffer[kSmallSize];
|
||||
int SmallSize;
|
||||
int Counts[16];
|
||||
int Size;
|
||||
public:
|
||||
Byte Buf[256];
|
||||
|
||||
Byte GetHead() const
|
||||
{
|
||||
if (SmallSize > 0)
|
||||
return SmallBuffer[kSmallSize - SmallSize];
|
||||
return Buf[0];
|
||||
}
|
||||
|
||||
void Init(int size)
|
||||
{
|
||||
Size = size;
|
||||
SmallSize = 0;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
Counts[i] = ((size >= 16) ? 16 : size);
|
||||
size -= Counts[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Add(unsigned pos, Byte val)
|
||||
{
|
||||
Buf[pos] = val;
|
||||
}
|
||||
|
||||
Byte GetAndMove(int pos)
|
||||
{
|
||||
if (pos < SmallSize)
|
||||
{
|
||||
Byte *p = SmallBuffer + kSmallSize - SmallSize;
|
||||
Byte res = p[pos];
|
||||
for (; pos > 0; pos--)
|
||||
p[pos] = p[pos - 1];
|
||||
SmallBuffer[kSmallSize - SmallSize] = res;
|
||||
return res;
|
||||
}
|
||||
if (SmallSize == kSmallSize)
|
||||
{
|
||||
int i = Size - 1;
|
||||
int g = 16;
|
||||
do
|
||||
{
|
||||
g--;
|
||||
int offset = (g << 4);
|
||||
for (int t = Counts[g] - 1; t >= 0; t--, i--)
|
||||
Buf[i] = Buf[offset + t];
|
||||
}
|
||||
while (g != 0);
|
||||
|
||||
for (i = kSmallSize - 1; i >= 0; i--)
|
||||
Buf[i] = SmallBuffer[i];
|
||||
Init(Size);
|
||||
}
|
||||
pos -= SmallSize;
|
||||
int g;
|
||||
for (g = 0; pos >= Counts[g]; g++)
|
||||
pos -= Counts[g];
|
||||
int offset = (g << 4);
|
||||
Byte res = Buf[offset + pos];
|
||||
for (pos; pos < 16 - 1; pos++)
|
||||
Buf[offset + pos] = Buf[offset + pos + 1];
|
||||
|
||||
SmallSize++;
|
||||
SmallBuffer[kSmallSize - SmallSize] = res;
|
||||
|
||||
Counts[g]--;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,170 @@
|
||||
// PpmdDecoder.cpp
|
||||
// 2009-03-11 : Igor Pavlov : Public domain
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "PpmdDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
static const UInt32 kBufSize = (1 << 20);
|
||||
|
||||
enum
|
||||
{
|
||||
kStatus_NeedInit,
|
||||
kStatus_Normal,
|
||||
kStatus_Finished,
|
||||
kStatus_Error
|
||||
};
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
::MidFree(_outBuf);
|
||||
Ppmd7_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
|
||||
{
|
||||
if (size < 5)
|
||||
return E_INVALIDARG;
|
||||
_order = props[0];
|
||||
UInt32 memSize = GetUi32(props + 1);
|
||||
if (_order < PPMD7_MIN_ORDER ||
|
||||
_order > PPMD7_MAX_ORDER ||
|
||||
memSize < PPMD7_MIN_MEM_SIZE ||
|
||||
memSize > PPMD7_MAX_MEM_SIZE)
|
||||
return E_NOTIMPL;
|
||||
if (!_inStream.Alloc(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
|
||||
{
|
||||
switch (_status)
|
||||
{
|
||||
case kStatus_Finished: return S_OK;
|
||||
case kStatus_Error: return S_FALSE;
|
||||
case kStatus_NeedInit:
|
||||
_inStream.Init();
|
||||
if (!Ppmd7z_RangeDec_Init(&_rangeDec))
|
||||
{
|
||||
_status = kStatus_Error;
|
||||
return S_FALSE;
|
||||
}
|
||||
_status = kStatus_Normal;
|
||||
Ppmd7_Init(&_ppmd, _order);
|
||||
break;
|
||||
}
|
||||
if (_outSizeDefined)
|
||||
{
|
||||
const UInt64 rem = _outSize - _processedSize;
|
||||
if (size > rem)
|
||||
size = (UInt32)rem;
|
||||
}
|
||||
|
||||
UInt32 i;
|
||||
int sym = 0;
|
||||
for (i = 0; i != size; i++)
|
||||
{
|
||||
sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.vt);
|
||||
if (_inStream.Extra || sym < 0)
|
||||
break;
|
||||
memStream[i] = (Byte)sym;
|
||||
}
|
||||
|
||||
_processedSize += i;
|
||||
if (_inStream.Extra)
|
||||
{
|
||||
_status = kStatus_Error;
|
||||
return _inStream.Res;
|
||||
}
|
||||
if (sym < 0)
|
||||
_status = (sym < -1) ? kStatus_Error : kStatus_Finished;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_outBuf)
|
||||
{
|
||||
_outBuf = (Byte *)::MidAlloc(kBufSize);
|
||||
if (!_outBuf)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
_inStream.Stream = inStream;
|
||||
SetOutStreamSize(outSize);
|
||||
|
||||
do
|
||||
{
|
||||
const UInt64 startPos = _processedSize;
|
||||
HRESULT res = CodeSpec(_outBuf, kBufSize);
|
||||
size_t processed = (size_t)(_processedSize - startPos);
|
||||
RINOK(WriteStream(outStream, _outBuf, processed));
|
||||
RINOK(res);
|
||||
if (_status == kStatus_Finished)
|
||||
break;
|
||||
if (progress)
|
||||
{
|
||||
UInt64 inSize = _inStream.GetProcessed();
|
||||
RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
|
||||
}
|
||||
}
|
||||
while (!_outSizeDefined || _processedSize < _outSize);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
||||
{
|
||||
_outSizeDefined = (outSize != NULL);
|
||||
if (_outSizeDefined)
|
||||
_outSize = *outSize;
|
||||
_processedSize = 0;
|
||||
_status = kStatus_NeedInit;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
*value = _inStream.GetProcessed();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
|
||||
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
|
||||
{
|
||||
InSeqStream = inStream;
|
||||
_inStream.Stream = inStream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::ReleaseInStream()
|
||||
{
|
||||
InSeqStream.Release();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
const UInt64 startPos = _processedSize;
|
||||
HRESULT res = CodeSpec((Byte *)data, size);
|
||||
if (processedSize)
|
||||
*processedSize = (UInt32)(_processedSize - startPos);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,86 @@
|
||||
// PpmdDecoder.h
|
||||
// 2009-03-11 : Igor Pavlov : Public domain
|
||||
|
||||
#ifndef __COMPRESS_PPMD_DECODER_H
|
||||
#define __COMPRESS_PPMD_DECODER_H
|
||||
|
||||
#include "../../../C/Ppmd7.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
class CDecoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetDecoderProperties2,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
public ICompressSetInStream,
|
||||
public ICompressSetOutStreamSize,
|
||||
public ISequentialInStream,
|
||||
#endif
|
||||
public CMyUnknownImp
|
||||
{
|
||||
Byte *_outBuf;
|
||||
CPpmd7z_RangeDec _rangeDec;
|
||||
CByteInBufWrap _inStream;
|
||||
CPpmd7 _ppmd;
|
||||
|
||||
Byte _order;
|
||||
bool _outSizeDefined;
|
||||
int _status;
|
||||
UInt64 _outSize;
|
||||
UInt64 _processedSize;
|
||||
|
||||
HRESULT CodeSpec(Byte *memStream, UInt32 size);
|
||||
|
||||
public:
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
CMyComPtr<ISequentialInStream> InSeqStream;
|
||||
#endif
|
||||
|
||||
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
|
||||
// MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
|
||||
MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
|
||||
#endif
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
|
||||
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
|
||||
|
||||
#ifndef NO_READ_FROM_CODER
|
||||
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
|
||||
STDMETHOD(ReleaseInStream)();
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
#endif
|
||||
|
||||
CDecoder(): _outBuf(NULL), _outSizeDefined(false)
|
||||
{
|
||||
Ppmd7z_RangeDec_CreateVTable(&_rangeDec);
|
||||
_rangeDec.Stream = &_inStream.vt;
|
||||
Ppmd7_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
~CDecoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,152 @@
|
||||
// PpmdEncoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "PpmdEncoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
static const UInt32 kBufSize = (1 << 20);
|
||||
|
||||
static const Byte kOrders[10] = { 3, 4, 4, 5, 5, 6, 8, 16, 24, 32 };
|
||||
|
||||
void CEncProps::Normalize(int level)
|
||||
{
|
||||
if (level < 0) level = 5;
|
||||
if (level > 9) level = 9;
|
||||
if (MemSize == (UInt32)(Int32)-1)
|
||||
MemSize = level >= 9 ? ((UInt32)192 << 20) : ((UInt32)1 << (level + 19));
|
||||
const unsigned kMult = 16;
|
||||
if (MemSize / kMult > ReduceSize)
|
||||
{
|
||||
for (unsigned i = 16; i <= 31; i++)
|
||||
{
|
||||
UInt32 m = (UInt32)1 << i;
|
||||
if (ReduceSize <= m / kMult)
|
||||
{
|
||||
if (MemSize > m)
|
||||
MemSize = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Order == -1) Order = kOrders[(unsigned)level];
|
||||
}
|
||||
|
||||
CEncoder::CEncoder():
|
||||
_inBuf(NULL)
|
||||
{
|
||||
_props.Normalize(-1);
|
||||
_rangeEnc.Stream = &_outStream.vt;
|
||||
Ppmd7_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
CEncoder::~CEncoder()
|
||||
{
|
||||
::MidFree(_inBuf);
|
||||
Ppmd7_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
|
||||
{
|
||||
int level = -1;
|
||||
CEncProps props;
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = coderProps[i];
|
||||
PROPID propID = propIDs[i];
|
||||
if (propID > NCoderPropID::kReduceSize)
|
||||
continue;
|
||||
if (propID == NCoderPropID::kReduceSize)
|
||||
{
|
||||
if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1)
|
||||
props.ReduceSize = (UInt32)prop.uhVal.QuadPart;
|
||||
continue;
|
||||
}
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
UInt32 v = (UInt32)prop.ulVal;
|
||||
switch (propID)
|
||||
{
|
||||
case NCoderPropID::kUsedMemorySize:
|
||||
if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0)
|
||||
return E_INVALIDARG;
|
||||
props.MemSize = v;
|
||||
break;
|
||||
case NCoderPropID::kOrder:
|
||||
if (v < 2 || v > 32)
|
||||
return E_INVALIDARG;
|
||||
props.Order = (Byte)v;
|
||||
break;
|
||||
case NCoderPropID::kNumThreads: break;
|
||||
case NCoderPropID::kLevel: level = (int)v; break;
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
props.Normalize(level);
|
||||
_props = props;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
|
||||
{
|
||||
const UInt32 kPropSize = 5;
|
||||
Byte props[kPropSize];
|
||||
props[0] = (Byte)_props.Order;
|
||||
SetUi32(props + 1, _props.MemSize);
|
||||
return WriteStream(outStream, props, kPropSize);
|
||||
}
|
||||
|
||||
HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_inBuf)
|
||||
{
|
||||
_inBuf = (Byte *)::MidAlloc(kBufSize);
|
||||
if (!_inBuf)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (!_outStream.Alloc(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!Ppmd7_Alloc(&_ppmd, _props.MemSize, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
_outStream.Stream = outStream;
|
||||
_outStream.Init();
|
||||
|
||||
Ppmd7z_RangeEnc_Init(&_rangeEnc);
|
||||
Ppmd7_Init(&_ppmd, _props.Order);
|
||||
|
||||
UInt64 processed = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 size;
|
||||
RINOK(inStream->Read(_inBuf, kBufSize, &size));
|
||||
if (size == 0)
|
||||
{
|
||||
// We don't write EndMark in PPMD-7z.
|
||||
// Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1);
|
||||
Ppmd7z_RangeEnc_FlushData(&_rangeEnc);
|
||||
return _outStream.Flush();
|
||||
}
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
{
|
||||
Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]);
|
||||
RINOK(_outStream.Res);
|
||||
}
|
||||
processed += size;
|
||||
if (progress)
|
||||
{
|
||||
UInt64 outSize = _outStream.GetProcessed();
|
||||
RINOK(progress->SetRatioInfo(&processed, &outSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,58 @@
|
||||
// PpmdEncoder.h
|
||||
|
||||
#ifndef __COMPRESS_PPMD_ENCODER_H
|
||||
#define __COMPRESS_PPMD_ENCODER_H
|
||||
|
||||
#include "../../../C/Ppmd7.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
struct CEncProps
|
||||
{
|
||||
UInt32 MemSize;
|
||||
UInt32 ReduceSize;
|
||||
int Order;
|
||||
|
||||
CEncProps()
|
||||
{
|
||||
MemSize = (UInt32)(Int32)-1;
|
||||
ReduceSize = (UInt32)(Int32)-1;
|
||||
Order = -1;
|
||||
}
|
||||
void Normalize(int level);
|
||||
};
|
||||
|
||||
class CEncoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
public ICompressWriteCoderProperties,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
Byte *_inBuf;
|
||||
CByteOutBufWrap _outStream;
|
||||
CPpmd7z_RangeEnc _rangeEnc;
|
||||
CPpmd7 _ppmd;
|
||||
CEncProps _props;
|
||||
public:
|
||||
MY_UNKNOWN_IMP3(
|
||||
ICompressCoder,
|
||||
ICompressSetCoderProperties,
|
||||
ICompressWriteCoderProperties)
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
|
||||
CEncoder();
|
||||
~CEncoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// PpmdRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "PpmdDecoder.h"
|
||||
|
||||
#ifndef EXTRACT_ONLY
|
||||
#include "PpmdEncoder.h"
|
||||
#endif
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmd {
|
||||
|
||||
REGISTER_CODEC_E(PPMD,
|
||||
CDecoder(),
|
||||
CEncoder(),
|
||||
0x30401,
|
||||
"PPMD")
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,287 @@
|
||||
// PpmdZip.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "PpmdZip.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmdZip {
|
||||
|
||||
CDecoder::CDecoder(bool fullFileMode):
|
||||
_fullFileMode(fullFileMode)
|
||||
{
|
||||
_ppmd.Stream.In = &_inStream.vt;
|
||||
Ppmd8_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
Ppmd8_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_outStream.Alloc())
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_inStream.Alloc(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
_inStream.Stream = inStream;
|
||||
_inStream.Init();
|
||||
|
||||
{
|
||||
Byte buf[2];
|
||||
for (int i = 0; i < 2; i++)
|
||||
buf[i] = _inStream.ReadByte();
|
||||
if (_inStream.Extra)
|
||||
return S_FALSE;
|
||||
|
||||
UInt32 val = GetUi16(buf);
|
||||
UInt32 order = (val & 0xF) + 1;
|
||||
UInt32 mem = ((val >> 4) & 0xFF) + 1;
|
||||
UInt32 restor = (val >> 12);
|
||||
if (order < 2 || restor > 2)
|
||||
return S_FALSE;
|
||||
|
||||
#ifndef PPMD8_FREEZE_SUPPORT
|
||||
if (restor == 2)
|
||||
return E_NOTIMPL;
|
||||
#endif
|
||||
|
||||
if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
if (!Ppmd8_RangeDec_Init(&_ppmd))
|
||||
return S_FALSE;
|
||||
Ppmd8_Init(&_ppmd, order, restor);
|
||||
}
|
||||
|
||||
bool wasFinished = false;
|
||||
UInt64 processedSize = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
size_t size = kBufSize;
|
||||
if (outSize)
|
||||
{
|
||||
const UInt64 rem = *outSize - processedSize;
|
||||
if (size > rem)
|
||||
{
|
||||
size = (size_t)rem;
|
||||
if (size == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Byte *data = _outStream.Buf;
|
||||
size_t i = 0;
|
||||
int sym = 0;
|
||||
do
|
||||
{
|
||||
sym = Ppmd8_DecodeSymbol(&_ppmd);
|
||||
if (_inStream.Extra || sym < 0)
|
||||
break;
|
||||
data[i] = (Byte)sym;
|
||||
}
|
||||
while (++i != size);
|
||||
|
||||
processedSize += i;
|
||||
|
||||
RINOK(WriteStream(outStream, _outStream.Buf, i));
|
||||
|
||||
RINOK(_inStream.Res);
|
||||
if (_inStream.Extra)
|
||||
return S_FALSE;
|
||||
|
||||
if (sym < 0)
|
||||
{
|
||||
if (sym != -1)
|
||||
return S_FALSE;
|
||||
wasFinished = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (progress)
|
||||
{
|
||||
const UInt64 inProccessed = _inStream.GetProcessed();
|
||||
RINOK(progress->SetRatioInfo(&inProccessed, &processedSize));
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(_inStream.Res);
|
||||
|
||||
if (_fullFileMode)
|
||||
{
|
||||
if (!wasFinished)
|
||||
{
|
||||
int res = Ppmd8_DecodeSymbol(&_ppmd);
|
||||
RINOK(_inStream.Res);
|
||||
if (_inStream.Extra || res != -1)
|
||||
return S_FALSE;
|
||||
}
|
||||
if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd))
|
||||
return S_FALSE;
|
||||
|
||||
if (inSize && *inSize != _inStream.GetProcessed())
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
|
||||
{
|
||||
_fullFileMode = (finishMode != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
*value = _inStream.GetProcessed();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------- Encoder ----------
|
||||
|
||||
void CEncProps::Normalize(int level)
|
||||
{
|
||||
if (level < 0) level = 5;
|
||||
if (level == 0) level = 1;
|
||||
if (level > 9) level = 9;
|
||||
if (MemSizeMB == (UInt32)(Int32)-1)
|
||||
MemSizeMB = (1 << ((level > 8 ? 8 : level) - 1));
|
||||
const unsigned kMult = 16;
|
||||
if ((MemSizeMB << 20) / kMult > ReduceSize)
|
||||
{
|
||||
for (UInt32 m = (1 << 20); m <= (1 << 28); m <<= 1)
|
||||
{
|
||||
if (ReduceSize <= m / kMult)
|
||||
{
|
||||
m >>= 20;
|
||||
if (MemSizeMB > m)
|
||||
MemSizeMB = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Order == -1) Order = 3 + level;
|
||||
if (Restor == -1)
|
||||
Restor = level < 7 ?
|
||||
PPMD8_RESTORE_METHOD_RESTART :
|
||||
PPMD8_RESTORE_METHOD_CUT_OFF;
|
||||
}
|
||||
|
||||
CEncoder::~CEncoder()
|
||||
{
|
||||
Ppmd8_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
|
||||
{
|
||||
int level = -1;
|
||||
CEncProps props;
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = coderProps[i];
|
||||
PROPID propID = propIDs[i];
|
||||
if (propID > NCoderPropID::kReduceSize)
|
||||
continue;
|
||||
if (propID == NCoderPropID::kReduceSize)
|
||||
{
|
||||
if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1)
|
||||
props.ReduceSize = (UInt32)prop.uhVal.QuadPart;
|
||||
continue;
|
||||
}
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
UInt32 v = (UInt32)prop.ulVal;
|
||||
switch (propID)
|
||||
{
|
||||
case NCoderPropID::kUsedMemorySize:
|
||||
if (v < (1 << 20) || v > (1 << 28))
|
||||
return E_INVALIDARG;
|
||||
props.MemSizeMB = v >> 20;
|
||||
break;
|
||||
case NCoderPropID::kOrder:
|
||||
if (v < PPMD8_MIN_ORDER || v > PPMD8_MAX_ORDER)
|
||||
return E_INVALIDARG;
|
||||
props.Order = (Byte)v;
|
||||
break;
|
||||
case NCoderPropID::kNumThreads: break;
|
||||
case NCoderPropID::kLevel: level = (int)v; break;
|
||||
case NCoderPropID::kAlgorithm:
|
||||
if (v > 1)
|
||||
return E_INVALIDARG;
|
||||
props.Restor = v;
|
||||
break;
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
}
|
||||
props.Normalize(level);
|
||||
_props = props;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
CEncoder::CEncoder()
|
||||
{
|
||||
_props.Normalize(-1);
|
||||
_ppmd.Stream.Out = &_outStream.vt;
|
||||
Ppmd8_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!_inStream.Alloc())
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_outStream.Alloc(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!Ppmd8_Alloc(&_ppmd, _props.MemSizeMB << 20, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
_outStream.Stream = outStream;
|
||||
_outStream.Init();
|
||||
|
||||
Ppmd8_RangeEnc_Init(&_ppmd);
|
||||
Ppmd8_Init(&_ppmd, _props.Order, _props.Restor);
|
||||
|
||||
UInt32 val = (UInt32)((_props.Order - 1) + ((_props.MemSizeMB - 1) << 4) + (_props.Restor << 12));
|
||||
_outStream.WriteByte((Byte)(val & 0xFF));
|
||||
_outStream.WriteByte((Byte)(val >> 8));
|
||||
RINOK(_outStream.Res);
|
||||
|
||||
UInt64 processed = 0;
|
||||
for (;;)
|
||||
{
|
||||
UInt32 size;
|
||||
RINOK(inStream->Read(_inStream.Buf, kBufSize, &size));
|
||||
if (size == 0)
|
||||
{
|
||||
Ppmd8_EncodeSymbol(&_ppmd, -1);
|
||||
Ppmd8_RangeEnc_FlushData(&_ppmd);
|
||||
return _outStream.Flush();
|
||||
}
|
||||
for (UInt32 i = 0; i < size; i++)
|
||||
{
|
||||
Ppmd8_EncodeSymbol(&_ppmd, _inStream.Buf[i]);
|
||||
RINOK(_outStream.Res);
|
||||
}
|
||||
processed += size;
|
||||
if (progress)
|
||||
{
|
||||
const UInt64 outProccessed = _outStream.GetProcessed();
|
||||
RINOK(progress->SetRatioInfo(&processed, &outProccessed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,97 @@
|
||||
// PpmdZip.h
|
||||
|
||||
#ifndef __COMPRESS_PPMD_ZIP_H
|
||||
#define __COMPRESS_PPMD_ZIP_H
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
#include "../../../C/Ppmd8.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NPpmdZip {
|
||||
|
||||
static const UInt32 kBufSize = (1 << 20);
|
||||
|
||||
struct CBuf
|
||||
{
|
||||
Byte *Buf;
|
||||
|
||||
CBuf(): Buf(0) {}
|
||||
~CBuf() { ::MidFree(Buf); }
|
||||
bool Alloc()
|
||||
{
|
||||
if (!Buf)
|
||||
Buf = (Byte *)::MidAlloc(kBufSize);
|
||||
return (Buf != 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CDecoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CByteInBufWrap _inStream;
|
||||
CBuf _outStream;
|
||||
CPpmd8 _ppmd;
|
||||
bool _fullFileMode;
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(
|
||||
ICompressSetFinishMode,
|
||||
ICompressGetInStreamProcessedSize)
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
|
||||
CDecoder(bool fullFileMode);
|
||||
~CDecoder();
|
||||
};
|
||||
|
||||
|
||||
struct CEncProps
|
||||
{
|
||||
UInt32 MemSizeMB;
|
||||
UInt32 ReduceSize;
|
||||
int Order;
|
||||
int Restor;
|
||||
|
||||
CEncProps()
|
||||
{
|
||||
MemSizeMB = (UInt32)(Int32)-1;
|
||||
ReduceSize = (UInt32)(Int32)-1;
|
||||
Order = -1;
|
||||
Restor = -1;
|
||||
}
|
||||
void Normalize(int level);
|
||||
};
|
||||
|
||||
class CEncoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CByteOutBufWrap _outStream;
|
||||
CBuf _inStream;
|
||||
CPpmd8 _ppmd;
|
||||
CEncProps _props;
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(ICompressSetCoderProperties)
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
CEncoder();
|
||||
~CEncoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,195 @@
|
||||
// QuantumDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/Defs.h"
|
||||
|
||||
#include "QuantumDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NQuantum {
|
||||
|
||||
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[(size_t)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[(size_t)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[(size_t)i + 1]);
|
||||
while (i--);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = NumItems - 1;
|
||||
do
|
||||
{
|
||||
Freqs[i] >>= 1;
|
||||
if (Freqs[i] <= Freqs[(size_t)i + 1])
|
||||
Freqs[i] = (UInt16)(Freqs[(size_t)i + 1] + 1);
|
||||
}
|
||||
while (i--);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void CDecoder::Init()
|
||||
{
|
||||
m_Selector.Init(kNumSelectors);
|
||||
unsigned i;
|
||||
for (i = 0; i < kNumLitSelectors; i++)
|
||||
m_Literals[i].Init(kNumLitSymbols);
|
||||
unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1));
|
||||
const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 };
|
||||
for (i = 0; i < kNumMatchSelectors; i++)
|
||||
m_PosSlot[i].Init(MyMin(numItems, kNumPosSymbolsMax[i]));
|
||||
m_LenSlot.Init(kNumLenSymbols);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize)
|
||||
{
|
||||
if (inSize < 2)
|
||||
return S_FALSE;
|
||||
|
||||
CRangeDecoder rc;
|
||||
rc.Stream.SetStreamAndInit(inData, inSize);
|
||||
rc.Init();
|
||||
|
||||
while (outSize != 0)
|
||||
{
|
||||
if (rc.Stream.WasExtraRead())
|
||||
return S_FALSE;
|
||||
|
||||
unsigned selector = m_Selector.Decode(&rc);
|
||||
|
||||
if (selector < kNumLitSelectors)
|
||||
{
|
||||
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(&rc);
|
||||
if (lenSlot >= kNumSimpleLenSlots)
|
||||
{
|
||||
lenSlot -= 2;
|
||||
unsigned numDirectBits = (unsigned)(lenSlot >> 2);
|
||||
len += ((4 | (lenSlot & 3)) << numDirectBits) - 2;
|
||||
if (numDirectBits < 6)
|
||||
len += rc.Stream.ReadBits(numDirectBits);
|
||||
}
|
||||
else
|
||||
len += lenSlot;
|
||||
}
|
||||
|
||||
UInt32 dist = m_PosSlot[selector].Decode(&rc);
|
||||
|
||||
if (dist >= kNumSimplePosSlots)
|
||||
{
|
||||
unsigned numDirectBits = (unsigned)((dist >> 1) - 1);
|
||||
dist = ((2 | (dist & 1)) << numDirectBits) + rc.Stream.ReadBits(numDirectBits);
|
||||
}
|
||||
|
||||
unsigned locLen = len;
|
||||
if (len > outSize)
|
||||
locLen = (unsigned)outSize;
|
||||
if (!_outWindow.CopyBlock(dist, locLen))
|
||||
return S_FALSE;
|
||||
outSize -= locLen;
|
||||
len -= locLen;
|
||||
if (len != 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return rc.Finish() ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::Code(const Byte *inData, size_t inSize,
|
||||
ISequentialOutStream *outStream, UInt32 outSize,
|
||||
bool keepHistory)
|
||||
{
|
||||
try
|
||||
{
|
||||
_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;
|
||||
}
|
||||
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
HRESULT CDecoder::SetParams(unsigned numDictBits)
|
||||
{
|
||||
if (numDictBits > 21)
|
||||
return E_INVALIDARG;
|
||||
_numDictBits = numDictBits;
|
||||
if (!_outWindow.Create((UInt32)1 << _numDictBits))
|
||||
return E_OUTOFMEMORY;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,175 @@
|
||||
// QuantumDecoder.h
|
||||
|
||||
#ifndef __COMPRESS_QUANTUM_DECODER_H
|
||||
#define __COMPRESS_QUANTUM_DECODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "LzOutWindow.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NQuantum {
|
||||
|
||||
class CBitDecoder
|
||||
{
|
||||
UInt32 Value;
|
||||
bool _extra;
|
||||
const Byte *_buf;
|
||||
const Byte *_bufLim;
|
||||
public:
|
||||
void SetStreamAndInit(const Byte *inData, size_t inSize)
|
||||
{
|
||||
_buf = inData;
|
||||
_bufLim = inData + inSize;
|
||||
Value = 0x10000;
|
||||
_extra = false;
|
||||
}
|
||||
|
||||
bool WasExtraRead() const { return _extra; }
|
||||
|
||||
bool WasFinishedOK() const
|
||||
{
|
||||
return !_extra && _buf == _bufLim;
|
||||
}
|
||||
|
||||
UInt32 ReadBit()
|
||||
{
|
||||
if (Value >= 0x10000)
|
||||
{
|
||||
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 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);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CRangeDecoder
|
||||
{
|
||||
UInt32 Low;
|
||||
UInt32 Range;
|
||||
UInt32 Code;
|
||||
public:
|
||||
CBitDecoder Stream;
|
||||
|
||||
void Init()
|
||||
{
|
||||
Low = 0;
|
||||
Range = 0x10000;
|
||||
Code = Stream.ReadStart16Bits();
|
||||
}
|
||||
|
||||
bool 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();
|
||||
}
|
||||
|
||||
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 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 Vals[kNumSymbolsMax];
|
||||
public:
|
||||
void Init(unsigned numItems);
|
||||
unsigned Decode(CRangeDecoder *rc);
|
||||
};
|
||||
|
||||
|
||||
class CDecoder:
|
||||
public IUnknown,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzOutWindow _outWindow;
|
||||
unsigned _numDictBits;
|
||||
|
||||
CModelDecoder m_Selector;
|
||||
CModelDecoder m_Literals[kNumLitSelectors];
|
||||
CModelDecoder m_PosSlot[kNumMatchSelectors];
|
||||
CModelDecoder m_LenSlot;
|
||||
|
||||
void Init();
|
||||
HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize);
|
||||
public:
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
HRESULT Code(const Byte *inData, size_t inSize,
|
||||
ISequentialOutStream *outStream, UInt32 outSize,
|
||||
bool keepHistory);
|
||||
|
||||
HRESULT SetParams(unsigned numDictBits);
|
||||
|
||||
CDecoder(): _numDictBits(0) {}
|
||||
virtual ~CDecoder() {}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,516 @@
|
||||
// Rar1Decoder.cpp
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Rar1Decoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NRar1 {
|
||||
|
||||
static const unsigned kNumBits = 12;
|
||||
|
||||
static const Byte kShortLen1[16 * 3] =
|
||||
{
|
||||
0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0,0,
|
||||
1,3,4,4,5,6,7,8,8,4,4,5,6,6,0,0,
|
||||
1,4,4,4,5,6,7,8,8,4,4,5,6,6,4,0
|
||||
};
|
||||
|
||||
static const Byte kShortLen2[16 * 3] =
|
||||
{
|
||||
0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0,0,
|
||||
2,3,3,3,4,4,5,6,6,4,4,5,6,6,0,0,
|
||||
2,3,3,4,4,4,5,6,6,4,4,5,6,6,4,0
|
||||
};
|
||||
|
||||
static const Byte PosL1[kNumBits + 1] = { 0,0,2,1,2,2,4,5,4,4,8,0,224 };
|
||||
static const Byte PosL2[kNumBits + 1] = { 0,0,0,5,2,2,4,5,4,4,8,2,220 };
|
||||
|
||||
static const Byte PosHf0[kNumBits + 1] = { 0,0,0,0,8,8,8,9,0,0,0,0,224 };
|
||||
static const Byte PosHf1[kNumBits + 1] = { 0,0,0,0,0,4,40,16,16,4,0,47,130 };
|
||||
static const Byte PosHf2[kNumBits + 1] = { 0,0,0,0,0,2,5,46,64,116,24,0,0 };
|
||||
static const Byte PosHf3[kNumBits + 1] = { 0,0,0,0,0,0,2,14,202,33,6,0,0 };
|
||||
static const Byte PosHf4[kNumBits + 1] = { 0,0,0,0,0,0,0,0,255,2,0,0,0 };
|
||||
|
||||
static const UInt32 kHistorySize = (1 << 16);
|
||||
|
||||
CDecoder::CDecoder():
|
||||
_isSolid(false),
|
||||
_solidAllowed(false)
|
||||
{ }
|
||||
|
||||
UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
|
||||
|
||||
HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len)
|
||||
{
|
||||
if (len == 0)
|
||||
return S_FALSE;
|
||||
if (m_UnpackSize < len)
|
||||
return S_FALSE;
|
||||
m_UnpackSize -= len;
|
||||
return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
|
||||
UInt32 CDecoder::DecodeNum(const Byte *numTab)
|
||||
{
|
||||
/*
|
||||
{
|
||||
// we can check that tables are correct
|
||||
UInt32 sum = 0;
|
||||
for (unsigned i = 0; i <= kNumBits; i++)
|
||||
sum += ((UInt32)numTab[i] << (kNumBits - i));
|
||||
if (sum != (1 << kNumBits))
|
||||
throw 111;
|
||||
}
|
||||
*/
|
||||
|
||||
UInt32 val = m_InBitStream.GetValue(kNumBits);
|
||||
UInt32 sum = 0;
|
||||
unsigned i = 2;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
UInt32 num = numTab[i];
|
||||
UInt32 cur = num << (kNumBits - i);
|
||||
if (val < cur)
|
||||
break;
|
||||
i++;
|
||||
val -= cur;
|
||||
sum += num;
|
||||
}
|
||||
m_InBitStream.MovePos(i);
|
||||
return ((val >> (kNumBits - i)) + sum);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::ShortLZ()
|
||||
{
|
||||
NumHuf = 0;
|
||||
|
||||
if (LCount == 2)
|
||||
{
|
||||
if (ReadBits(1))
|
||||
return CopyBlock(LastDist, LastLength);
|
||||
LCount = 0;
|
||||
}
|
||||
|
||||
UInt32 bitField = m_InBitStream.GetValue(8);
|
||||
|
||||
UInt32 len, dist;
|
||||
{
|
||||
const Byte *xors = (AvrLn1 < 37) ? kShortLen1 : kShortLen2;
|
||||
const Byte *lens = xors + 16 + Buf60;
|
||||
for (len = 0; ((bitField ^ xors[len]) >> (8 - lens[len])) != 0; len++);
|
||||
m_InBitStream.MovePos(lens[len]);
|
||||
}
|
||||
|
||||
if (len >= 9)
|
||||
{
|
||||
if (len == 9)
|
||||
{
|
||||
LCount++;
|
||||
return CopyBlock(LastDist, LastLength);
|
||||
}
|
||||
|
||||
LCount = 0;
|
||||
|
||||
if (len == 14)
|
||||
{
|
||||
len = DecodeNum(PosL2) + 5;
|
||||
dist = 0x8000 + ReadBits(15) - 1;
|
||||
LastLength = len;
|
||||
LastDist = dist;
|
||||
return CopyBlock(dist, len);
|
||||
}
|
||||
|
||||
UInt32 saveLen = len;
|
||||
dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3];
|
||||
|
||||
len = DecodeNum(PosL1);
|
||||
|
||||
if (len == 0xff && saveLen == 10)
|
||||
{
|
||||
Buf60 ^= 16;
|
||||
return S_OK;
|
||||
}
|
||||
if (dist >= 256)
|
||||
{
|
||||
len++;
|
||||
if (dist >= MaxDist3 - 1)
|
||||
len++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LCount = 0;
|
||||
AvrLn1 += len;
|
||||
AvrLn1 -= AvrLn1 >> 4;
|
||||
|
||||
unsigned distancePlace = DecodeNum(PosHf2) & 0xff;
|
||||
|
||||
dist = ChSetA[distancePlace];
|
||||
|
||||
if (distancePlace != 0)
|
||||
{
|
||||
PlaceA[dist]--;
|
||||
UInt32 lastDistance = ChSetA[(size_t)distancePlace - 1];
|
||||
PlaceA[lastDistance]++;
|
||||
ChSetA[distancePlace] = lastDistance;
|
||||
ChSetA[(size_t)distancePlace - 1] = dist;
|
||||
}
|
||||
}
|
||||
|
||||
m_RepDists[m_RepDistPtr++] = dist;
|
||||
m_RepDistPtr &= 3;
|
||||
len += 2;
|
||||
LastLength = len;
|
||||
LastDist = dist;
|
||||
return CopyBlock(dist, len);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::LongLZ()
|
||||
{
|
||||
UInt32 len;
|
||||
UInt32 dist;
|
||||
UInt32 distancePlace, newDistancePlace;
|
||||
UInt32 oldAvr2, oldAvr3;
|
||||
|
||||
NumHuf = 0;
|
||||
Nlzb += 16;
|
||||
if (Nlzb > 0xff)
|
||||
{
|
||||
Nlzb = 0x90;
|
||||
Nhfb >>= 1;
|
||||
}
|
||||
oldAvr2 = AvrLn2;
|
||||
|
||||
if (AvrLn2 >= 64)
|
||||
len = DecodeNum(AvrLn2 < 122 ? PosL1 : PosL2);
|
||||
else
|
||||
{
|
||||
UInt32 bitField = m_InBitStream.GetValue(16);
|
||||
if (bitField < 0x100)
|
||||
{
|
||||
len = bitField;
|
||||
m_InBitStream.MovePos(16);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (len = 0; ((bitField << len) & 0x8000) == 0; len++);
|
||||
|
||||
m_InBitStream.MovePos(len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
AvrLn2 += len;
|
||||
AvrLn2 -= AvrLn2 >> 5;
|
||||
|
||||
{
|
||||
const Byte *tab;
|
||||
if (AvrPlcB >= 0x2900) tab = PosHf2;
|
||||
else if (AvrPlcB >= 0x0700) tab = PosHf1;
|
||||
else tab = PosHf0;
|
||||
distancePlace = DecodeNum(tab); // [0, 256]
|
||||
}
|
||||
|
||||
AvrPlcB += distancePlace;
|
||||
AvrPlcB -= AvrPlcB >> 8;
|
||||
|
||||
distancePlace &= 0xff;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
dist = ChSetB[distancePlace];
|
||||
newDistancePlace = NToPlB[dist++ & 0xff]++;
|
||||
if (dist & 0xff)
|
||||
break;
|
||||
CorrHuff(ChSetB,NToPlB);
|
||||
}
|
||||
|
||||
ChSetB[distancePlace] = ChSetB[newDistancePlace];
|
||||
ChSetB[newDistancePlace] = dist;
|
||||
|
||||
dist = ((dist & 0xff00) >> 1) | ReadBits(7);
|
||||
|
||||
oldAvr3 = AvrLn3;
|
||||
|
||||
if (len != 1 && len != 4)
|
||||
if (len == 0 && dist <= MaxDist3)
|
||||
{
|
||||
AvrLn3++;
|
||||
AvrLn3 -= AvrLn3 >> 8;
|
||||
}
|
||||
else if (AvrLn3 > 0)
|
||||
AvrLn3--;
|
||||
|
||||
len += 3;
|
||||
|
||||
if (dist >= MaxDist3)
|
||||
len++;
|
||||
if (dist <= 256)
|
||||
len += 8;
|
||||
|
||||
if (oldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && oldAvr2 < 0x40)
|
||||
MaxDist3 = 0x7f00;
|
||||
else
|
||||
MaxDist3 = 0x2001;
|
||||
|
||||
m_RepDists[m_RepDistPtr++] = --dist;
|
||||
m_RepDistPtr &= 3;
|
||||
LastLength = len;
|
||||
LastDist = dist;
|
||||
|
||||
return CopyBlock(dist, len);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::HuffDecode()
|
||||
{
|
||||
UInt32 curByte, newBytePlace;
|
||||
UInt32 len;
|
||||
UInt32 dist;
|
||||
unsigned bytePlace;
|
||||
{
|
||||
const Byte *tab;
|
||||
|
||||
if (AvrPlc >= 0x7600) tab = PosHf4;
|
||||
else if (AvrPlc >= 0x5e00) tab = PosHf3;
|
||||
else if (AvrPlc >= 0x3600) tab = PosHf2;
|
||||
else if (AvrPlc >= 0x0e00) tab = PosHf1;
|
||||
else tab = PosHf0;
|
||||
|
||||
bytePlace = DecodeNum(tab); // [0, 256]
|
||||
}
|
||||
|
||||
if (StMode)
|
||||
{
|
||||
if (bytePlace == 0)
|
||||
{
|
||||
if (ReadBits(1))
|
||||
{
|
||||
NumHuf = 0;
|
||||
StMode = false;
|
||||
return S_OK;
|
||||
}
|
||||
len = ReadBits(1) + 3;
|
||||
dist = DecodeNum(PosHf2);
|
||||
dist = (dist << 5) | ReadBits(5);
|
||||
if (dist == 0)
|
||||
return S_FALSE;
|
||||
return CopyBlock(dist - 1, len);
|
||||
}
|
||||
bytePlace--; // bytePlace is [0, 255]
|
||||
}
|
||||
else if (NumHuf++ >= 16 && FlagsCnt == 0)
|
||||
StMode = true;
|
||||
|
||||
bytePlace &= 0xff;
|
||||
AvrPlc += bytePlace;
|
||||
AvrPlc -= AvrPlc >> 8;
|
||||
Nhfb += 16;
|
||||
|
||||
if (Nhfb > 0xff)
|
||||
{
|
||||
Nhfb = 0x90;
|
||||
Nlzb >>= 1;
|
||||
}
|
||||
|
||||
m_UnpackSize--;
|
||||
m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8));
|
||||
|
||||
for (;;)
|
||||
{
|
||||
curByte = ChSet[bytePlace];
|
||||
newBytePlace = NToPl[curByte++ & 0xff]++;
|
||||
if ((curByte & 0xff) <= 0xa1)
|
||||
break;
|
||||
CorrHuff(ChSet, NToPl);
|
||||
}
|
||||
|
||||
ChSet[bytePlace] = ChSet[newBytePlace];
|
||||
ChSet[newBytePlace] = curByte;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
void CDecoder::GetFlagsBuf()
|
||||
{
|
||||
UInt32 flags, newFlagsPlace;
|
||||
UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256]
|
||||
|
||||
if (flagsPlace >= ARRAY_SIZE(ChSetC))
|
||||
return;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
flags = ChSetC[flagsPlace];
|
||||
FlagBuf = flags >> 8;
|
||||
newFlagsPlace = NToPlC[flags++ & 0xff]++;
|
||||
if ((flags & 0xff) != 0)
|
||||
break;
|
||||
CorrHuff(ChSetC, NToPlC);
|
||||
}
|
||||
|
||||
ChSetC[flagsPlace] = ChSetC[newFlagsPlace];
|
||||
ChSetC[newFlagsPlace] = flags;
|
||||
}
|
||||
|
||||
|
||||
void CDecoder::CorrHuff(UInt32 *CharSet,UInt32 *NumToPlace)
|
||||
{
|
||||
int i;
|
||||
for (i = 7; i >= 0; i--)
|
||||
for (int j = 0; j < 32; j++, CharSet++)
|
||||
*CharSet = (*CharSet & ~0xff) | i;
|
||||
memset(NumToPlace, 0, sizeof(NToPl));
|
||||
for (i = 6; i >= 0; i--)
|
||||
NumToPlace[i] = (7 - i) * 32;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */)
|
||||
{
|
||||
if (!inSize || !outSize)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (_isSolid && !_solidAllowed)
|
||||
return S_FALSE;
|
||||
|
||||
_solidAllowed = false;
|
||||
|
||||
if (!m_OutWindowStream.Create(kHistorySize))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!m_InBitStream.Create(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
m_UnpackSize = *outSize;
|
||||
|
||||
m_OutWindowStream.SetStream(outStream);
|
||||
m_OutWindowStream.Init(_isSolid);
|
||||
m_InBitStream.SetStream(inStream);
|
||||
m_InBitStream.Init();
|
||||
|
||||
// InitData
|
||||
|
||||
FlagsCnt = 0;
|
||||
FlagBuf = 0;
|
||||
StMode = false;
|
||||
LCount = 0;
|
||||
|
||||
if (!_isSolid)
|
||||
{
|
||||
AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0;
|
||||
AvrPlc = 0x3500;
|
||||
MaxDist3 = 0x2001;
|
||||
Nhfb = Nlzb = 0x80;
|
||||
|
||||
{
|
||||
// InitStructures
|
||||
for (int i = 0; i < kNumRepDists; i++)
|
||||
m_RepDists[i] = 0;
|
||||
m_RepDistPtr = 0;
|
||||
LastLength = 0;
|
||||
LastDist = 0;
|
||||
}
|
||||
|
||||
// InitHuff
|
||||
|
||||
for (UInt32 i = 0; i < 256; i++)
|
||||
{
|
||||
Place[i] = PlaceA[i] = PlaceB[i] = i;
|
||||
UInt32 c = (~i + 1) & 0xff;
|
||||
PlaceC[i] = c;
|
||||
ChSet[i] = ChSetB[i] = i << 8;
|
||||
ChSetA[i] = i;
|
||||
ChSetC[i] = c << 8;
|
||||
}
|
||||
memset(NToPl, 0, sizeof(NToPl));
|
||||
memset(NToPlB, 0, sizeof(NToPlB));
|
||||
memset(NToPlC, 0, sizeof(NToPlC));
|
||||
CorrHuff(ChSetB, NToPlB);
|
||||
}
|
||||
|
||||
if (m_UnpackSize > 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt = 8;
|
||||
}
|
||||
|
||||
while (m_UnpackSize != 0)
|
||||
{
|
||||
if (!StMode)
|
||||
{
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
|
||||
if (FlagBuf & 0x80)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
if (Nlzb > Nhfb)
|
||||
{
|
||||
RINOK(LongLZ());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
|
||||
if (--FlagsCnt < 0)
|
||||
{
|
||||
GetFlagsBuf();
|
||||
FlagsCnt = 7;
|
||||
}
|
||||
|
||||
if ((FlagBuf & 0x80) == 0)
|
||||
{
|
||||
FlagBuf <<= 1;
|
||||
RINOK(ShortLZ());
|
||||
continue;
|
||||
}
|
||||
|
||||
FlagBuf <<= 1;
|
||||
|
||||
if (Nlzb <= Nhfb)
|
||||
{
|
||||
RINOK(LongLZ());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(HuffDecode());
|
||||
}
|
||||
|
||||
_solidAllowed = true;
|
||||
return m_OutWindowStream.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::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
{
|
||||
if (size < 1)
|
||||
return E_INVALIDARG;
|
||||
_isSolid = ((data[0] & 1) != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,79 @@
|
||||
// Rar1Decoder.h
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
#ifndef __COMPRESS_RAR1_DECODER_H
|
||||
#define __COMPRESS_RAR1_DECODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
|
||||
#include "BitmDecoder.h"
|
||||
#include "HuffmanDecoder.h"
|
||||
#include "LzOutWindow.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NRar1 {
|
||||
|
||||
const UInt32 kNumRepDists = 4;
|
||||
|
||||
class CDecoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetDecoderProperties2,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzOutWindow m_OutWindowStream;
|
||||
NBitm::CDecoder<CInBuffer> m_InBitStream;
|
||||
|
||||
UInt64 m_UnpackSize;
|
||||
|
||||
UInt32 LastDist;
|
||||
UInt32 LastLength;
|
||||
|
||||
UInt32 m_RepDistPtr;
|
||||
UInt32 m_RepDists[kNumRepDists];
|
||||
|
||||
bool _isSolid;
|
||||
bool _solidAllowed;
|
||||
|
||||
bool StMode;
|
||||
int FlagsCnt;
|
||||
UInt32 FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3;
|
||||
unsigned Buf60, NumHuf, LCount;
|
||||
UInt32 Nhfb, Nlzb, MaxDist3;
|
||||
|
||||
UInt32 ChSet[256], ChSetA[256], ChSetB[256], ChSetC[256];
|
||||
UInt32 Place[256], PlaceA[256], PlaceB[256], PlaceC[256];
|
||||
UInt32 NToPl[256], NToPlB[256], NToPlC[256];
|
||||
|
||||
UInt32 ReadBits(unsigned numBits);
|
||||
HRESULT CopyBlock(UInt32 distance, UInt32 len);
|
||||
UInt32 DecodeNum(const Byte *numTab);
|
||||
HRESULT ShortLZ();
|
||||
HRESULT LongLZ();
|
||||
HRESULT HuffDecode();
|
||||
void GetFlagsBuf();
|
||||
void CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace);
|
||||
void OldUnpWriteBuf();
|
||||
|
||||
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
public:
|
||||
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
|
||||
@@ -0,0 +1,435 @@
|
||||
// Rar2Decoder.cpp
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Rar2Decoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NRar2 {
|
||||
|
||||
namespace NMultimedia {
|
||||
|
||||
Byte CFilter::Decode(int &channelDelta, Byte deltaByte)
|
||||
{
|
||||
D4 = D3;
|
||||
D3 = D2;
|
||||
D2 = LastDelta - D1;
|
||||
D1 = LastDelta;
|
||||
int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3);
|
||||
|
||||
Byte realValue = (Byte)(predictedValue - deltaByte);
|
||||
|
||||
{
|
||||
int i = ((int)(signed char)deltaByte) << 3;
|
||||
|
||||
Dif[0] += abs(i);
|
||||
Dif[1] += abs(i - D1);
|
||||
Dif[2] += abs(i + D1);
|
||||
Dif[3] += abs(i - D2);
|
||||
Dif[4] += abs(i + D2);
|
||||
Dif[5] += abs(i - D3);
|
||||
Dif[6] += abs(i + D3);
|
||||
Dif[7] += abs(i - D4);
|
||||
Dif[8] += abs(i + D4);
|
||||
Dif[9] += abs(i - channelDelta);
|
||||
Dif[10] += abs(i + channelDelta);
|
||||
}
|
||||
|
||||
channelDelta = LastDelta = (signed char)(realValue - LastChar);
|
||||
LastChar = realValue;
|
||||
|
||||
if (((++ByteCount) & 0x1F) == 0)
|
||||
{
|
||||
UInt32 minDif = Dif[0];
|
||||
UInt32 numMinDif = 0;
|
||||
Dif[0] = 0;
|
||||
|
||||
for (unsigned i = 1; i < ARRAY_SIZE(Dif); i++)
|
||||
{
|
||||
if (Dif[i] < minDif)
|
||||
{
|
||||
minDif = Dif[i];
|
||||
numMinDif = i;
|
||||
}
|
||||
Dif[i] = 0;
|
||||
}
|
||||
|
||||
switch (numMinDif)
|
||||
{
|
||||
case 1: if (K1 >= -16) K1--; break;
|
||||
case 2: if (K1 < 16) K1++; break;
|
||||
case 3: if (K2 >= -16) K2--; break;
|
||||
case 4: if (K2 < 16) K2++; break;
|
||||
case 5: if (K3 >= -16) K3--; break;
|
||||
case 6: if (K3 < 16) K3++; break;
|
||||
case 7: if (K4 >= -16) K4--; break;
|
||||
case 8: if (K4 < 16) K4++; break;
|
||||
case 9: if (K5 >= -16) K5--; break;
|
||||
case 10:if (K5 < 16) K5++; break;
|
||||
}
|
||||
}
|
||||
|
||||
return realValue;
|
||||
}
|
||||
}
|
||||
|
||||
static const UInt32 kHistorySize = 1 << 20;
|
||||
|
||||
static const UInt32 kWindowReservSize = (1 << 22) + 256;
|
||||
|
||||
CDecoder::CDecoder():
|
||||
_isSolid(false),
|
||||
_solidAllowed(false),
|
||||
m_TablesOK(false)
|
||||
{
|
||||
}
|
||||
|
||||
void CDecoder::InitStructures()
|
||||
{
|
||||
m_MmFilter.Init();
|
||||
for (unsigned i = 0; i < kNumRepDists; i++)
|
||||
m_RepDists[i] = 0;
|
||||
m_RepDistPtr = 0;
|
||||
m_LastLength = 0;
|
||||
memset(m_LastLevels, 0, kMaxTableSize);
|
||||
}
|
||||
|
||||
UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
|
||||
|
||||
#define RIF(x) { if (!(x)) return false; }
|
||||
|
||||
bool CDecoder::ReadTables(void)
|
||||
{
|
||||
m_TablesOK = false;
|
||||
|
||||
Byte levelLevels[kLevelTableSize];
|
||||
Byte lens[kMaxTableSize];
|
||||
|
||||
m_AudioMode = (ReadBits(1) == 1);
|
||||
|
||||
if (ReadBits(1) == 0)
|
||||
memset(m_LastLevels, 0, kMaxTableSize);
|
||||
|
||||
unsigned numLevels;
|
||||
|
||||
if (m_AudioMode)
|
||||
{
|
||||
m_NumChannels = ReadBits(2) + 1;
|
||||
if (m_MmFilter.CurrentChannel >= m_NumChannels)
|
||||
m_MmFilter.CurrentChannel = 0;
|
||||
numLevels = m_NumChannels * kMMTableSize;
|
||||
}
|
||||
else
|
||||
numLevels = kHeapTablesSizesSum;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < kLevelTableSize; i++)
|
||||
levelLevels[i] = (Byte)ReadBits(4);
|
||||
RIF(m_LevelDecoder.Build(levelLevels));
|
||||
|
||||
i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
|
||||
if (sym < kTableDirectLevels)
|
||||
{
|
||||
lens[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sym == kTableLevelRepNumber)
|
||||
{
|
||||
unsigned num = ReadBits(2) + 3;
|
||||
if (i == 0)
|
||||
return false;
|
||||
num += i;
|
||||
if (num > numLevels)
|
||||
{
|
||||
// return false;
|
||||
num = numLevels; // original unRAR
|
||||
}
|
||||
Byte v = lens[(size_t)i - 1];
|
||||
do
|
||||
lens[i++] = v;
|
||||
while (i < num);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned num;
|
||||
if (sym == kTableLevel0Number)
|
||||
num = ReadBits(3) + 3;
|
||||
else if (sym == kTableLevel0Number2)
|
||||
num = ReadBits(7) + 11;
|
||||
else
|
||||
return false;
|
||||
num += i;
|
||||
if (num > numLevels)
|
||||
{
|
||||
// return false;
|
||||
num = numLevels; // original unRAR
|
||||
}
|
||||
do
|
||||
lens[i++] = 0;
|
||||
while (i < num);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (i < numLevels);
|
||||
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
|
||||
if (m_AudioMode)
|
||||
for (i = 0; i < m_NumChannels; i++)
|
||||
{
|
||||
RIF(m_MMDecoders[i].Build(&lens[i * kMMTableSize]));
|
||||
}
|
||||
else
|
||||
{
|
||||
RIF(m_MainDecoder.Build(&lens[0]));
|
||||
RIF(m_DistDecoder.Build(&lens[kMainTableSize]));
|
||||
RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize]));
|
||||
}
|
||||
|
||||
memcpy(m_LastLevels, lens, kMaxTableSize);
|
||||
|
||||
m_TablesOK = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDecoder::ReadLastTables()
|
||||
{
|
||||
// it differs a little from pure RAR sources;
|
||||
// UInt64 ttt = m_InBitStream.GetProcessedSize() + 2;
|
||||
// + 2 works for: return 0xFF; in CInBuffer::ReadByte.
|
||||
if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect;
|
||||
// if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
|
||||
if (m_AudioMode)
|
||||
{
|
||||
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
|
||||
if (symbol == 256)
|
||||
return ReadTables();
|
||||
if (symbol >= kMMTableSize)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
|
||||
if (sym == kReadTableNumber)
|
||||
return ReadTables();
|
||||
if (sym >= kMainTableSize)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CDecoder::DecodeMm(UInt32 pos)
|
||||
{
|
||||
while (pos-- != 0)
|
||||
{
|
||||
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
if (symbol >= 256)
|
||||
return symbol == 256;
|
||||
/*
|
||||
Byte byPredict = m_Predictor.Predict();
|
||||
Byte byReal = (Byte)(byPredict - (Byte)symbol);
|
||||
m_Predictor.Update(byReal, byPredict);
|
||||
*/
|
||||
Byte byReal = m_MmFilter.Decode((Byte)symbol);
|
||||
m_OutWindowStream.PutByte(byReal);
|
||||
if (++m_MmFilter.CurrentChannel == m_NumChannels)
|
||||
m_MmFilter.CurrentChannel = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDecoder::DecodeLz(Int32 pos)
|
||||
{
|
||||
while (pos > 0)
|
||||
{
|
||||
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return false;
|
||||
UInt32 length, distance;
|
||||
if (sym < 256)
|
||||
{
|
||||
m_OutWindowStream.PutByte(Byte(sym));
|
||||
pos--;
|
||||
continue;
|
||||
}
|
||||
else if (sym >= kMatchNumber)
|
||||
{
|
||||
if (sym >= kMainTableSize)
|
||||
return false;
|
||||
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[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
|
||||
if (distance >= kDistLimit3)
|
||||
{
|
||||
length += 2 - ((distance - kDistLimit4) >> 31);
|
||||
// length++;
|
||||
// if (distance >= kDistLimit4)
|
||||
// length++;
|
||||
}
|
||||
}
|
||||
else if (sym == kRepBothNumber)
|
||||
{
|
||||
length = m_LastLength;
|
||||
if (length == 0)
|
||||
return false;
|
||||
distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
|
||||
}
|
||||
else if (sym < kLen2Number)
|
||||
{
|
||||
distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3];
|
||||
sym = m_LenDecoder.Decode(&m_InBitStream);
|
||||
if (sym >= kLenTableSize)
|
||||
return false;
|
||||
length = 2 + kLenStart[sym] + m_InBitStream.ReadBits(kLenDirectBits[sym]);
|
||||
if (distance >= kDistLimit2)
|
||||
{
|
||||
length++;
|
||||
if (distance >= kDistLimit3)
|
||||
{
|
||||
length += 2 - ((distance - kDistLimit4) >> 31);
|
||||
// length++;
|
||||
// if (distance >= kDistLimit4)
|
||||
// length++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sym < kReadTableNumber)
|
||||
{
|
||||
sym -= kLen2Number;
|
||||
distance = kLen2DistStarts[sym] +
|
||||
m_InBitStream.ReadBits(kLen2DistDirectBits[sym]);
|
||||
length = 2;
|
||||
}
|
||||
else // (sym == kReadTableNumber)
|
||||
return true;
|
||||
|
||||
m_RepDists[m_RepDistPtr++ & 3] = distance;
|
||||
m_LastLength = length;
|
||||
if (!m_OutWindowStream.CopyBlock(distance, length))
|
||||
return false;
|
||||
pos -= length;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
if (!inSize || !outSize)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (_isSolid && !_solidAllowed)
|
||||
return S_FALSE;
|
||||
_solidAllowed = false;
|
||||
|
||||
if (!m_OutWindowStream.Create(kHistorySize))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!m_InBitStream.Create(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
m_PackSize = *inSize;
|
||||
|
||||
UInt64 pos = 0, unPackSize = *outSize;
|
||||
|
||||
m_OutWindowStream.SetStream(outStream);
|
||||
m_OutWindowStream.Init(_isSolid);
|
||||
m_InBitStream.SetStream(inStream);
|
||||
m_InBitStream.Init();
|
||||
|
||||
// CCoderReleaser coderReleaser(this);
|
||||
if (!_isSolid)
|
||||
{
|
||||
InitStructures();
|
||||
if (unPackSize == 0)
|
||||
{
|
||||
if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
|
||||
if (!ReadTables())
|
||||
return S_FALSE;
|
||||
_solidAllowed = true;
|
||||
return S_OK;
|
||||
}
|
||||
ReadTables();
|
||||
}
|
||||
|
||||
if (!m_TablesOK)
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 startPos = m_OutWindowStream.GetProcessedSize();
|
||||
while (pos < unPackSize)
|
||||
{
|
||||
UInt32 blockSize = 1 << 20;
|
||||
if (blockSize > unPackSize - pos)
|
||||
blockSize = (UInt32)(unPackSize - pos);
|
||||
UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize();
|
||||
if (m_AudioMode)
|
||||
{
|
||||
if (!DecodeMm(blockSize))
|
||||
return S_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!DecodeLz((Int32)blockSize))
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (m_InBitStream.ExtraBitsWereRead())
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 globalPos = m_OutWindowStream.GetProcessedSize();
|
||||
pos = globalPos - blockStartPos;
|
||||
if (pos < blockSize)
|
||||
if (!ReadTables())
|
||||
return S_FALSE;
|
||||
pos = globalPos - startPos;
|
||||
if (progress)
|
||||
{
|
||||
const UInt64 packSize = m_InBitStream.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &pos));
|
||||
}
|
||||
}
|
||||
if (pos > unPackSize)
|
||||
return S_FALSE;
|
||||
|
||||
if (!ReadLastTables())
|
||||
return S_FALSE;
|
||||
|
||||
_solidAllowed = true;
|
||||
|
||||
return m_OutWindowStream.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::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
{
|
||||
if (size < 1)
|
||||
return E_INVALIDARG;
|
||||
_isSolid = ((data[0] & 1) != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,172 @@
|
||||
// Rar2Decoder.h
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
#ifndef __COMPRESS_RAR2_DECODER_H
|
||||
#define __COMPRESS_RAR2_DECODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
|
||||
#include "BitmDecoder.h"
|
||||
#include "HuffmanDecoder.h"
|
||||
#include "LzOutWindow.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NRar2 {
|
||||
|
||||
const unsigned kNumRepDists = 4;
|
||||
const unsigned kDistTableSize = 48;
|
||||
|
||||
const unsigned kMMTableSize = 256 + 1;
|
||||
|
||||
const UInt32 kMainTableSize = 298;
|
||||
const UInt32 kLenTableSize = 28;
|
||||
|
||||
const UInt32 kDistTableStart = kMainTableSize;
|
||||
const UInt32 kLenTableStart = kDistTableStart + kDistTableSize;
|
||||
|
||||
const UInt32 kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize;
|
||||
|
||||
const UInt32 kLevelTableSize = 19;
|
||||
|
||||
const UInt32 kMMTablesSizesSum = kMMTableSize * 4;
|
||||
|
||||
const UInt32 kMaxTableSize = kMMTablesSizesSum;
|
||||
|
||||
const UInt32 kTableDirectLevels = 16;
|
||||
const UInt32 kTableLevelRepNumber = kTableDirectLevels;
|
||||
const UInt32 kTableLevel0Number = kTableLevelRepNumber + 1;
|
||||
const UInt32 kTableLevel0Number2 = kTableLevel0Number + 1;
|
||||
|
||||
const UInt32 kLevelMask = 0xF;
|
||||
|
||||
|
||||
const UInt32 kRepBothNumber = 256;
|
||||
const UInt32 kRepNumber = kRepBothNumber + 1;
|
||||
const UInt32 kLen2Number = kRepNumber + 4;
|
||||
|
||||
const UInt32 kLen2NumNumbers = 8;
|
||||
const UInt32 kReadTableNumber = kLen2Number + kLen2NumNumbers;
|
||||
const UInt32 kMatchNumber = kReadTableNumber + 1;
|
||||
|
||||
const Byte kLenStart [kLenTableSize] = {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
|
||||
const Byte kLenDirectBits[kLenTableSize] = {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
|
||||
|
||||
const UInt32 kDistStart [kDistTableSize] = {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
|
||||
const Byte kDistDirectBits[kDistTableSize] = {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
|
||||
|
||||
const Byte kLevelDirectBits[kLevelTableSize] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
|
||||
|
||||
const Byte kLen2DistStarts[kLen2NumNumbers]={0,4,8,16,32,64,128,192};
|
||||
const Byte kLen2DistDirectBits[kLen2NumNumbers]={2,2,3, 4, 5, 6, 6, 6};
|
||||
|
||||
const UInt32 kDistLimit2 = 0x101 - 1;
|
||||
const UInt32 kDistLimit3 = 0x2000 - 1;
|
||||
const UInt32 kDistLimit4 = 0x40000 - 1;
|
||||
|
||||
const UInt32 kMatchMaxLen = 255 + 2;
|
||||
const UInt32 kMatchMaxLenMax = 255 + 5;
|
||||
const UInt32 kNormalMatchMinLen = 3;
|
||||
|
||||
namespace NMultimedia {
|
||||
|
||||
struct CFilter
|
||||
{
|
||||
int K1,K2,K3,K4,K5;
|
||||
int D1,D2,D3,D4;
|
||||
int LastDelta;
|
||||
UInt32 Dif[11];
|
||||
UInt32 ByteCount;
|
||||
int LastChar;
|
||||
|
||||
Byte Decode(int &channelDelta, Byte delta);
|
||||
|
||||
void Init() { memset(this, 0, sizeof(*this)); }
|
||||
|
||||
};
|
||||
|
||||
const unsigned kNumChanelsMax = 4;
|
||||
|
||||
class CFilter2
|
||||
{
|
||||
public:
|
||||
CFilter m_Filters[kNumChanelsMax];
|
||||
int m_ChannelDelta;
|
||||
unsigned CurrentChannel;
|
||||
|
||||
void Init() { memset(this, 0, sizeof(*this)); }
|
||||
Byte Decode(Byte delta)
|
||||
{
|
||||
return m_Filters[CurrentChannel].Decode(m_ChannelDelta, delta);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
typedef NBitm::CDecoder<CInBuffer> CBitDecoder;
|
||||
|
||||
const unsigned kNumHuffmanBits = 15;
|
||||
|
||||
class CDecoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetDecoderProperties2,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CLzOutWindow m_OutWindowStream;
|
||||
CBitDecoder m_InBitStream;
|
||||
|
||||
UInt32 m_RepDistPtr;
|
||||
UInt32 m_RepDists[kNumRepDists];
|
||||
|
||||
UInt32 m_LastLength;
|
||||
|
||||
bool _isSolid;
|
||||
bool _solidAllowed;
|
||||
bool m_TablesOK;
|
||||
bool m_AudioMode;
|
||||
|
||||
NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
|
||||
NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
|
||||
NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
|
||||
NHuffman::CDecoder<kNumHuffmanBits, kMMTableSize> m_MMDecoders[NMultimedia::kNumChanelsMax];
|
||||
NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
|
||||
|
||||
UInt64 m_PackSize;
|
||||
|
||||
unsigned m_NumChannels;
|
||||
NMultimedia::CFilter2 m_MmFilter;
|
||||
|
||||
Byte m_LastLevels[kMaxTableSize];
|
||||
|
||||
|
||||
void InitStructures();
|
||||
UInt32 ReadBits(unsigned numBits);
|
||||
bool ReadTables();
|
||||
bool ReadLastTables();
|
||||
|
||||
bool DecodeMm(UInt32 pos);
|
||||
bool DecodeLz(Int32 pos);
|
||||
|
||||
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
public:
|
||||
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
|
||||
@@ -0,0 +1,960 @@
|
||||
// Rar3Decoder.cpp
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "Rar3Decoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NRar3 {
|
||||
|
||||
static const UInt32 kNumAlignReps = 15;
|
||||
|
||||
static const UInt32 kSymbolReadTable = 256;
|
||||
static const UInt32 kSymbolRep = 259;
|
||||
static const UInt32 kSymbolLen2 = kSymbolRep + kNumReps;
|
||||
|
||||
static const Byte kLenStart [kLenTableSize] = {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
|
||||
static const Byte kLenDirectBits[kLenTableSize] = {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
|
||||
|
||||
static const Byte kDistDirectBits[kDistTableSize] =
|
||||
{0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,
|
||||
16,16,16,16,16,16,16,16,16,16,16,16,16,16,
|
||||
18,18,18,18,18,18,18,18,18,18,18,18};
|
||||
|
||||
static const Byte kLevelDirectBits[kLevelTableSize] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
|
||||
|
||||
static const Byte kLen2DistStarts[kNumLen2Symbols]={0,4,8,16,32,64,128,192};
|
||||
static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6};
|
||||
|
||||
static const UInt32 kDistLimit3 = 0x2000 - 2;
|
||||
static const UInt32 kDistLimit4 = 0x40000 - 2;
|
||||
|
||||
static const UInt32 kNormalMatchMinLen = 3;
|
||||
|
||||
static const UInt32 kVmDataSizeMax = 1 << 16;
|
||||
static const UInt32 kVmCodeSizeMax = 1 << 16;
|
||||
|
||||
extern "C" {
|
||||
|
||||
#define GET_RangeDecoder CRangeDecoder *p = CONTAINER_FROM_VTBL_CLS(pp, CRangeDecoder, vt);
|
||||
|
||||
static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total)
|
||||
{
|
||||
GET_RangeDecoder;
|
||||
return p->Code / (p->Range /= total);
|
||||
}
|
||||
|
||||
static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size)
|
||||
{
|
||||
GET_RangeDecoder;
|
||||
start *= p->Range;
|
||||
p->Low += start;
|
||||
p->Code -= start;
|
||||
p->Range *= size;
|
||||
p->Normalize();
|
||||
}
|
||||
|
||||
static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0)
|
||||
{
|
||||
GET_RangeDecoder;
|
||||
if (p->Code / (p->Range >>= 14) < size0)
|
||||
{
|
||||
Range_Decode(&p->vt, 0, size0);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Range_Decode(&p->vt, size0, (1 << 14) - size0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CRangeDecoder::CRangeDecoder() throw()
|
||||
{
|
||||
vt.GetThreshold = Range_GetThreshold;
|
||||
vt.Decode = Range_Decode;
|
||||
vt.DecodeBit = Range_DecodeBit;
|
||||
}
|
||||
|
||||
CDecoder::CDecoder():
|
||||
_window(0),
|
||||
_winPos(0),
|
||||
_wrPtr(0),
|
||||
_lzSize(0),
|
||||
_writtenFileSize(0),
|
||||
_vmData(0),
|
||||
_vmCode(0),
|
||||
_isSolid(false),
|
||||
_solidAllowed(false)
|
||||
{
|
||||
Ppmd7_Construct(&_ppmd);
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
InitFilters();
|
||||
::MidFree(_vmData);
|
||||
::MidFree(_window);
|
||||
Ppmd7_Free(&_ppmd, &g_BigAlloc);
|
||||
}
|
||||
|
||||
HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size)
|
||||
{
|
||||
return WriteStream(_outStream, data, size);
|
||||
}
|
||||
|
||||
HRESULT CDecoder::WriteData(const Byte *data, UInt32 size)
|
||||
{
|
||||
HRESULT res = S_OK;
|
||||
if (_writtenFileSize < _unpackSize)
|
||||
{
|
||||
UInt32 curSize = size;
|
||||
UInt64 remain = _unpackSize - _writtenFileSize;
|
||||
if (remain < curSize)
|
||||
curSize = (UInt32)remain;
|
||||
res = WriteDataToStream(data, curSize);
|
||||
}
|
||||
_writtenFileSize += size;
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr)
|
||||
{
|
||||
if (startPtr <= endPtr)
|
||||
return WriteData(_window + startPtr, endPtr - startPtr);
|
||||
RINOK(WriteData(_window + startPtr, kWindowSize - startPtr));
|
||||
return WriteData(_window, endPtr);
|
||||
}
|
||||
|
||||
void CDecoder::ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef)
|
||||
{
|
||||
CTempFilter *tempFilter = _tempFilters[tempFilterIndex];
|
||||
tempFilter->InitR[6] = (UInt32)_writtenFileSize;
|
||||
NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize);
|
||||
NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32));
|
||||
CFilter *filter = _filters[tempFilter->FilterIndex];
|
||||
if (!filter->IsSupported)
|
||||
_unsupportedFilter = true;
|
||||
if (!_vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData))
|
||||
_unsupportedFilter = true;
|
||||
delete tempFilter;
|
||||
_tempFilters[tempFilterIndex] = NULL;
|
||||
_numEmptyTempFilters++;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::WriteBuf()
|
||||
{
|
||||
UInt32 writtenBorder = _wrPtr;
|
||||
UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask;
|
||||
FOR_VECTOR (i, _tempFilters)
|
||||
{
|
||||
CTempFilter *filter = _tempFilters[i];
|
||||
if (!filter)
|
||||
continue;
|
||||
if (filter->NextWindow)
|
||||
{
|
||||
filter->NextWindow = false;
|
||||
continue;
|
||||
}
|
||||
UInt32 blockStart = filter->BlockStart;
|
||||
UInt32 blockSize = filter->BlockSize;
|
||||
if (((blockStart - writtenBorder) & kWindowMask) < writeSize)
|
||||
{
|
||||
if (writtenBorder != blockStart)
|
||||
{
|
||||
RINOK(WriteArea(writtenBorder, blockStart));
|
||||
writtenBorder = blockStart;
|
||||
writeSize = (_winPos - writtenBorder) & kWindowMask;
|
||||
}
|
||||
if (blockSize <= writeSize)
|
||||
{
|
||||
UInt32 blockEnd = (blockStart + blockSize) & kWindowMask;
|
||||
if (blockStart < blockEnd || blockEnd == 0)
|
||||
_vm.SetMemory(0, _window + blockStart, blockSize);
|
||||
else
|
||||
{
|
||||
UInt32 tailSize = kWindowSize - blockStart;
|
||||
_vm.SetMemory(0, _window + blockStart, tailSize);
|
||||
_vm.SetMemory(tailSize, _window, blockEnd);
|
||||
}
|
||||
NVm::CBlockRef outBlockRef;
|
||||
ExecuteFilter(i, outBlockRef);
|
||||
while (i + 1 < _tempFilters.Size())
|
||||
{
|
||||
CTempFilter *nextFilter = _tempFilters[i + 1];
|
||||
if (!nextFilter
|
||||
|| nextFilter->BlockStart != blockStart
|
||||
|| nextFilter->BlockSize != outBlockRef.Size
|
||||
|| nextFilter->NextWindow)
|
||||
break;
|
||||
_vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
|
||||
ExecuteFilter(++i, outBlockRef);
|
||||
}
|
||||
WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
|
||||
_writtenFileSize += outBlockRef.Size;
|
||||
writtenBorder = blockEnd;
|
||||
writeSize = (_winPos - writtenBorder) & kWindowMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned j = i; j < _tempFilters.Size(); j++)
|
||||
{
|
||||
CTempFilter *filter2 = _tempFilters[j];
|
||||
if (filter2 && filter2->NextWindow)
|
||||
filter2->NextWindow = false;
|
||||
}
|
||||
_wrPtr = writtenBorder;
|
||||
return S_OK; // check it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_wrPtr = _winPos;
|
||||
return WriteArea(writtenBorder, _winPos);
|
||||
}
|
||||
|
||||
void CDecoder::InitFilters()
|
||||
{
|
||||
_lastFilter = 0;
|
||||
_numEmptyTempFilters = 0;
|
||||
unsigned i;
|
||||
for (i = 0; i < _tempFilters.Size(); i++)
|
||||
delete _tempFilters[i];
|
||||
_tempFilters.Clear();
|
||||
for (i = 0; i < _filters.Size(); i++)
|
||||
delete _filters[i];
|
||||
_filters.Clear();
|
||||
}
|
||||
|
||||
static const unsigned MAX_UNPACK_FILTERS = 8192;
|
||||
|
||||
bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
|
||||
{
|
||||
CMemBitDecoder inp;
|
||||
inp.Init(_vmData, codeSize);
|
||||
|
||||
UInt32 filterIndex;
|
||||
|
||||
if (firstByte & 0x80)
|
||||
{
|
||||
filterIndex = inp.ReadEncodedUInt32();
|
||||
if (filterIndex == 0)
|
||||
InitFilters();
|
||||
else
|
||||
filterIndex--;
|
||||
}
|
||||
else
|
||||
filterIndex = _lastFilter;
|
||||
|
||||
if (filterIndex > (UInt32)_filters.Size())
|
||||
return false;
|
||||
_lastFilter = filterIndex;
|
||||
bool newFilter = (filterIndex == (UInt32)_filters.Size());
|
||||
|
||||
CFilter *filter;
|
||||
if (newFilter)
|
||||
{
|
||||
// check if too many filters
|
||||
if (filterIndex > MAX_UNPACK_FILTERS)
|
||||
return false;
|
||||
filter = new CFilter;
|
||||
_filters.Add(filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
filter = _filters[filterIndex];
|
||||
filter->ExecCount++;
|
||||
}
|
||||
|
||||
if (_numEmptyTempFilters != 0)
|
||||
{
|
||||
unsigned num = _tempFilters.Size();
|
||||
CTempFilter **tempFilters = &_tempFilters.Front();
|
||||
|
||||
unsigned w = 0;
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
{
|
||||
CTempFilter *tf = tempFilters[i];
|
||||
if (tf)
|
||||
tempFilters[w++] = tf;
|
||||
}
|
||||
|
||||
_tempFilters.DeleteFrom(w);
|
||||
_numEmptyTempFilters = 0;
|
||||
}
|
||||
|
||||
if (_tempFilters.Size() > MAX_UNPACK_FILTERS)
|
||||
return false;
|
||||
CTempFilter *tempFilter = new CTempFilter;
|
||||
_tempFilters.Add(tempFilter);
|
||||
tempFilter->FilterIndex = filterIndex;
|
||||
|
||||
UInt32 blockStart = inp.ReadEncodedUInt32();
|
||||
if (firstByte & 0x40)
|
||||
blockStart += 258;
|
||||
tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask;
|
||||
if (firstByte & 0x20)
|
||||
filter->BlockSize = inp.ReadEncodedUInt32();
|
||||
tempFilter->BlockSize = filter->BlockSize;
|
||||
tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart;
|
||||
|
||||
memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR));
|
||||
tempFilter->InitR[3] = NVm::kGlobalOffset;
|
||||
tempFilter->InitR[4] = tempFilter->BlockSize;
|
||||
tempFilter->InitR[5] = filter->ExecCount;
|
||||
if (firstByte & 0x10)
|
||||
{
|
||||
UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs);
|
||||
for (unsigned i = 0; i < NVm::kNumGpRegs; i++)
|
||||
if (initMask & (1 << i))
|
||||
tempFilter->InitR[i] = inp.ReadEncodedUInt32();
|
||||
}
|
||||
|
||||
bool isOK = true;
|
||||
if (newFilter)
|
||||
{
|
||||
UInt32 vmCodeSize = inp.ReadEncodedUInt32();
|
||||
if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0)
|
||||
return false;
|
||||
for (UInt32 i = 0; i < vmCodeSize; i++)
|
||||
_vmCode[i] = (Byte)inp.ReadBits(8);
|
||||
isOK = filter->PrepareProgram(_vmCode, vmCodeSize);
|
||||
}
|
||||
|
||||
{
|
||||
Byte *globalData = &tempFilter->GlobalData[0];
|
||||
for (unsigned i = 0; i < NVm::kNumGpRegs; i++)
|
||||
NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]);
|
||||
NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize);
|
||||
NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why?
|
||||
NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], filter->ExecCount);
|
||||
}
|
||||
|
||||
if (firstByte & 8)
|
||||
{
|
||||
UInt32 dataSize = inp.ReadEncodedUInt32();
|
||||
if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize)
|
||||
return false;
|
||||
CRecordVector<Byte> &globalData = tempFilter->GlobalData;
|
||||
unsigned requiredSize = (unsigned)(dataSize + NVm::kFixedGlobalSize);
|
||||
if (globalData.Size() < requiredSize)
|
||||
globalData.ChangeSize_KeepData(requiredSize);
|
||||
Byte *dest = &globalData[NVm::kFixedGlobalSize];
|
||||
for (UInt32 i = 0; i < dataSize; i++)
|
||||
dest[i] = (Byte)inp.ReadBits(8);
|
||||
}
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
bool CDecoder::ReadVmCodeLZ()
|
||||
{
|
||||
UInt32 firstByte = ReadBits(8);
|
||||
UInt32 length = (firstByte & 7) + 1;
|
||||
if (length == 7)
|
||||
length = ReadBits(8) + 7;
|
||||
else if (length == 8)
|
||||
length = ReadBits(16);
|
||||
if (length > kVmDataSizeMax)
|
||||
return false;
|
||||
for (UInt32 i = 0; i < length; i++)
|
||||
_vmData[i] = (Byte)ReadBits(8);
|
||||
return AddVmCode(firstByte, length);
|
||||
}
|
||||
|
||||
bool CDecoder::ReadVmCodePPM()
|
||||
{
|
||||
int firstByte = DecodePpmSymbol();
|
||||
if (firstByte < 0)
|
||||
return false;
|
||||
UInt32 length = (firstByte & 7) + 1;
|
||||
if (length == 7)
|
||||
{
|
||||
int b1 = DecodePpmSymbol();
|
||||
if (b1 < 0)
|
||||
return false;
|
||||
length = b1 + 7;
|
||||
}
|
||||
else if (length == 8)
|
||||
{
|
||||
int b1 = DecodePpmSymbol();
|
||||
if (b1 < 0)
|
||||
return false;
|
||||
int b2 = DecodePpmSymbol();
|
||||
if (b2 < 0)
|
||||
return false;
|
||||
length = b1 * 256 + b2;
|
||||
}
|
||||
if (length > kVmDataSizeMax)
|
||||
return false;
|
||||
if (InputEofError_Fast())
|
||||
return false;
|
||||
for (UInt32 i = 0; i < length; i++)
|
||||
{
|
||||
int b = DecodePpmSymbol();
|
||||
if (b < 0)
|
||||
return false;
|
||||
_vmData[i] = (Byte)b;
|
||||
}
|
||||
return AddVmCode(firstByte, length);
|
||||
}
|
||||
|
||||
#define RIF(x) { if (!(x)) return S_FALSE; }
|
||||
|
||||
UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); }
|
||||
|
||||
// ---------- PPM ----------
|
||||
|
||||
HRESULT CDecoder::InitPPM()
|
||||
{
|
||||
unsigned maxOrder = (unsigned)ReadBits(7);
|
||||
|
||||
bool reset = ((maxOrder & 0x20) != 0);
|
||||
UInt32 maxMB = 0;
|
||||
if (reset)
|
||||
maxMB = (Byte)ReadBits(8);
|
||||
else
|
||||
{
|
||||
if (PpmError || !Ppmd7_WasAllocated(&_ppmd))
|
||||
return S_FALSE;
|
||||
}
|
||||
if (maxOrder & 0x40)
|
||||
PpmEscChar = (Byte)ReadBits(8);
|
||||
m_InBitStream.InitRangeCoder();
|
||||
/*
|
||||
if (m_InBitStream.m_BitPos != 0)
|
||||
return S_FALSE;
|
||||
*/
|
||||
if (reset)
|
||||
{
|
||||
PpmError = true;
|
||||
maxOrder = (maxOrder & 0x1F) + 1;
|
||||
if (maxOrder > 16)
|
||||
maxOrder = 16 + (maxOrder - 16) * 3;
|
||||
if (maxOrder == 1)
|
||||
{
|
||||
Ppmd7_Free(&_ppmd, &g_BigAlloc);
|
||||
return S_FALSE;
|
||||
}
|
||||
if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc))
|
||||
return E_OUTOFMEMORY;
|
||||
Ppmd7_Init(&_ppmd, maxOrder);
|
||||
PpmError = false;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int CDecoder::DecodePpmSymbol() { return Ppmd7_DecodeSymbol(&_ppmd, &m_InBitStream.vt); }
|
||||
|
||||
HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
|
||||
{
|
||||
keepDecompressing = false;
|
||||
if (PpmError)
|
||||
return S_FALSE;
|
||||
do
|
||||
{
|
||||
if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
|
||||
{
|
||||
RINOK(WriteBuf());
|
||||
if (_writtenFileSize > _unpackSize)
|
||||
{
|
||||
keepDecompressing = false;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
if (InputEofError_Fast())
|
||||
return false;
|
||||
int c = DecodePpmSymbol();
|
||||
if (c < 0)
|
||||
{
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
if (c == PpmEscChar)
|
||||
{
|
||||
int nextCh = DecodePpmSymbol();
|
||||
if (nextCh < 0)
|
||||
{
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
if (nextCh == 0)
|
||||
return ReadTables(keepDecompressing);
|
||||
if (nextCh == 2 || nextCh == -1)
|
||||
return S_OK;
|
||||
if (nextCh == 3)
|
||||
{
|
||||
if (!ReadVmCodePPM())
|
||||
{
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (nextCh == 4 || nextCh == 5)
|
||||
{
|
||||
UInt32 distance = 0;
|
||||
UInt32 length = 4;
|
||||
if (nextCh == 4)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
int c2 = DecodePpmSymbol();
|
||||
if (c2 < 0)
|
||||
{
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
distance = (distance << 8) + (Byte)c2;
|
||||
}
|
||||
distance++;
|
||||
length += 28;
|
||||
}
|
||||
int c2 = DecodePpmSymbol();
|
||||
if (c2 < 0)
|
||||
{
|
||||
PpmError = true;
|
||||
return S_FALSE;
|
||||
}
|
||||
length += c2;
|
||||
if (distance >= _lzSize)
|
||||
return S_FALSE;
|
||||
CopyBlock(distance, length);
|
||||
num -= (Int32)length;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
PutByte((Byte)c);
|
||||
num--;
|
||||
}
|
||||
while (num >= 0);
|
||||
keepDecompressing = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// ---------- LZ ----------
|
||||
|
||||
HRESULT CDecoder::ReadTables(bool &keepDecompressing)
|
||||
{
|
||||
keepDecompressing = true;
|
||||
m_InBitStream.BitDecoder.AlignToByte();
|
||||
if (ReadBits(1) != 0)
|
||||
{
|
||||
_lzMode = false;
|
||||
return InitPPM();
|
||||
}
|
||||
|
||||
TablesRead = false;
|
||||
TablesOK = false;
|
||||
|
||||
_lzMode = true;
|
||||
PrevAlignBits = 0;
|
||||
PrevAlignCount = 0;
|
||||
|
||||
Byte levelLevels[kLevelTableSize];
|
||||
Byte lens[kTablesSizesSum];
|
||||
|
||||
if (ReadBits(1) == 0)
|
||||
memset(m_LastLevels, 0, kTablesSizesSum);
|
||||
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < kLevelTableSize; i++)
|
||||
{
|
||||
UInt32 length = ReadBits(4);
|
||||
if (length == 15)
|
||||
{
|
||||
UInt32 zeroCount = ReadBits(4);
|
||||
if (zeroCount != 0)
|
||||
{
|
||||
zeroCount += 2;
|
||||
while (zeroCount-- > 0 && i < kLevelTableSize)
|
||||
levelLevels[i++]=0;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
levelLevels[i] = (Byte)length;
|
||||
}
|
||||
|
||||
RIF(m_LevelDecoder.Build(levelLevels));
|
||||
|
||||
i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder);
|
||||
if (sym < 16)
|
||||
{
|
||||
lens[i] = Byte((sym + m_LastLevels[i]) & 15);
|
||||
i++;
|
||||
}
|
||||
else if (sym > kLevelTableSize)
|
||||
return S_FALSE;
|
||||
else
|
||||
{
|
||||
unsigned num = ((sym - 16) & 1) * 4;
|
||||
num += num + 3 + (unsigned)ReadBits(num + 3);
|
||||
num += i;
|
||||
if (num > kTablesSizesSum)
|
||||
num = kTablesSizesSum;
|
||||
Byte v = 0;
|
||||
if (sym < 16 + 2)
|
||||
{
|
||||
if (i == 0)
|
||||
return S_FALSE;
|
||||
v = lens[(size_t)i - 1];
|
||||
}
|
||||
do
|
||||
lens[i++] = v;
|
||||
while (i < num);
|
||||
}
|
||||
}
|
||||
while (i < kTablesSizesSum);
|
||||
|
||||
if (InputEofError())
|
||||
return S_FALSE;
|
||||
|
||||
TablesRead = true;
|
||||
|
||||
// original code has check here:
|
||||
/*
|
||||
if (InAddr > ReadTop)
|
||||
{
|
||||
keepDecompressing = false;
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
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]));
|
||||
|
||||
memcpy(m_LastLevels, lens, kTablesSizesSum);
|
||||
|
||||
TablesOK = true;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
class CCoderReleaser
|
||||
{
|
||||
CDecoder *m_Coder;
|
||||
public:
|
||||
CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
|
||||
~CCoderReleaser()
|
||||
{
|
||||
m_Coder->ReleaseStreams();
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
|
||||
{
|
||||
if (ReadBits(1) == 0)
|
||||
{
|
||||
// new file
|
||||
keepDecompressing = false;
|
||||
TablesRead = (ReadBits(1) == 0);
|
||||
return S_OK;
|
||||
}
|
||||
TablesRead = false;
|
||||
return ReadTables(keepDecompressing);
|
||||
}
|
||||
|
||||
UInt32 kDistStart[kDistTableSize];
|
||||
|
||||
class CDistInit
|
||||
{
|
||||
public:
|
||||
CDistInit() { Init(); }
|
||||
void Init()
|
||||
{
|
||||
UInt32 start = 0;
|
||||
for (UInt32 i = 0; i < kDistTableSize; i++)
|
||||
{
|
||||
kDistStart[i] = start;
|
||||
start += (1 << kDistDirectBits[i]);
|
||||
}
|
||||
}
|
||||
} g_DistInit;
|
||||
|
||||
HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
|
||||
{
|
||||
UInt32 rep0 = _reps[0];
|
||||
UInt32 rep1 = _reps[1];
|
||||
UInt32 rep2 = _reps[2];
|
||||
UInt32 rep3 = _reps[3];
|
||||
UInt32 length = _lastLength;
|
||||
for (;;)
|
||||
{
|
||||
if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
|
||||
{
|
||||
RINOK(WriteBuf());
|
||||
if (_writtenFileSize > _unpackSize)
|
||||
{
|
||||
keepDecompressing = false;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (InputEofError_Fast())
|
||||
return S_FALSE;
|
||||
|
||||
UInt32 sym = m_MainDecoder.Decode(&m_InBitStream.BitDecoder);
|
||||
if (sym < 256)
|
||||
{
|
||||
PutByte((Byte)sym);
|
||||
continue;
|
||||
}
|
||||
else if (sym == kSymbolReadTable)
|
||||
{
|
||||
RINOK(ReadEndOfBlock(keepDecompressing));
|
||||
break;
|
||||
}
|
||||
else if (sym == 257)
|
||||
{
|
||||
if (!ReadVmCodeLZ())
|
||||
return S_FALSE;
|
||||
continue;
|
||||
}
|
||||
else if (sym == 258)
|
||||
{
|
||||
if (length == 0)
|
||||
return S_FALSE;
|
||||
}
|
||||
else if (sym < kSymbolRep + 4)
|
||||
{
|
||||
if (sym != kSymbolRep)
|
||||
{
|
||||
UInt32 distance;
|
||||
if (sym == kSymbolRep + 1)
|
||||
distance = rep1;
|
||||
else
|
||||
{
|
||||
if (sym == kSymbolRep + 2)
|
||||
distance = rep2;
|
||||
else
|
||||
{
|
||||
distance = rep3;
|
||||
rep3 = rep2;
|
||||
}
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
|
||||
const UInt32 sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder);
|
||||
if (sym2 >= kLenTableSize)
|
||||
return S_FALSE;
|
||||
length = 2 + kLenStart[sym2] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rep3 = rep2;
|
||||
rep2 = rep1;
|
||||
rep1 = rep0;
|
||||
if (sym < 271)
|
||||
{
|
||||
sym -= 263;
|
||||
rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits(kLen2DistDirectBits[sym]);
|
||||
length = 2;
|
||||
}
|
||||
else if (sym < 299)
|
||||
{
|
||||
sym -= 271;
|
||||
length = kNormalMatchMinLen + (UInt32)kLenStart[sym] + m_InBitStream.BitDecoder.ReadBits(kLenDirectBits[sym]);
|
||||
const UInt32 sym2 = m_DistDecoder.Decode(&m_InBitStream.BitDecoder);
|
||||
if (sym2 >= kDistTableSize)
|
||||
return S_FALSE;
|
||||
rep0 = kDistStart[sym2];
|
||||
unsigned numBits = kDistDirectBits[sym2];
|
||||
if (sym2 >= (kNumAlignBits * 2) + 2)
|
||||
{
|
||||
if (numBits > kNumAlignBits)
|
||||
rep0 += (m_InBitStream.BitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
|
||||
if (PrevAlignCount > 0)
|
||||
{
|
||||
PrevAlignCount--;
|
||||
rep0 += PrevAlignBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
const UInt32 sym3 = m_AlignDecoder.Decode(&m_InBitStream.BitDecoder);
|
||||
if (sym3 < (1 << kNumAlignBits))
|
||||
{
|
||||
rep0 += sym3;
|
||||
PrevAlignBits = sym3;
|
||||
}
|
||||
else if (sym3 == (1 << kNumAlignBits))
|
||||
{
|
||||
PrevAlignCount = kNumAlignReps;
|
||||
rep0 += PrevAlignBits;
|
||||
}
|
||||
else
|
||||
return S_FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
rep0 += m_InBitStream.BitDecoder.ReadBits(numBits);
|
||||
length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31);
|
||||
}
|
||||
else
|
||||
return S_FALSE;
|
||||
}
|
||||
if (rep0 >= _lzSize)
|
||||
return S_FALSE;
|
||||
CopyBlock(rep0, length);
|
||||
}
|
||||
_reps[0] = rep0;
|
||||
_reps[1] = rep1;
|
||||
_reps[2] = rep2;
|
||||
_reps[3] = rep3;
|
||||
_lastLength = length;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
|
||||
{
|
||||
_writtenFileSize = 0;
|
||||
_unsupportedFilter = false;
|
||||
|
||||
if (!_isSolid)
|
||||
{
|
||||
_lzSize = 0;
|
||||
_winPos = 0;
|
||||
_wrPtr = 0;
|
||||
for (int i = 0; i < kNumReps; i++)
|
||||
_reps[i] = 0;
|
||||
_lastLength = 0;
|
||||
memset(m_LastLevels, 0, kTablesSizesSum);
|
||||
TablesRead = false;
|
||||
PpmEscChar = 2;
|
||||
PpmError = true;
|
||||
InitFilters();
|
||||
// _errorMode = false;
|
||||
}
|
||||
|
||||
/*
|
||||
if (_errorMode)
|
||||
return S_FALSE;
|
||||
*/
|
||||
|
||||
if (!_isSolid || !TablesRead)
|
||||
{
|
||||
bool keepDecompressing;
|
||||
RINOK(ReadTables(keepDecompressing));
|
||||
if (!keepDecompressing)
|
||||
{
|
||||
_solidAllowed = true;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
bool keepDecompressing;
|
||||
if (_lzMode)
|
||||
{
|
||||
if (!TablesOK)
|
||||
return S_FALSE;
|
||||
RINOK(DecodeLZ(keepDecompressing))
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(DecodePPM(1 << 18, keepDecompressing))
|
||||
}
|
||||
|
||||
if (InputEofError())
|
||||
return S_FALSE;
|
||||
|
||||
UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
|
||||
if (!keepDecompressing)
|
||||
break;
|
||||
}
|
||||
|
||||
_solidAllowed = true;
|
||||
|
||||
RINOK(WriteBuf());
|
||||
UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
|
||||
if (_writtenFileSize < _unpackSize)
|
||||
return S_FALSE;
|
||||
|
||||
if (_unsupportedFilter)
|
||||
return E_NOTIMPL;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!inSize)
|
||||
return E_INVALIDARG;
|
||||
|
||||
if (_isSolid && !_solidAllowed)
|
||||
return S_FALSE;
|
||||
_solidAllowed = false;
|
||||
|
||||
if (!_vmData)
|
||||
{
|
||||
_vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
|
||||
if (!_vmData)
|
||||
return E_OUTOFMEMORY;
|
||||
_vmCode = _vmData + kVmDataSizeMax;
|
||||
}
|
||||
|
||||
if (!_window)
|
||||
{
|
||||
_window = (Byte *)::MidAlloc(kWindowSize);
|
||||
if (!_window)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
if (!m_InBitStream.BitDecoder.Create(1 << 20))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!_vm.Create())
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
|
||||
m_InBitStream.BitDecoder.SetStream(inStream);
|
||||
m_InBitStream.BitDecoder.Init();
|
||||
_outStream = outStream;
|
||||
|
||||
// CCoderReleaser coderReleaser(this);
|
||||
_unpackSize = outSize ? *outSize : (UInt64)(Int64)-1;
|
||||
return CodeReal(progress);
|
||||
}
|
||||
catch(const CInBufferException &e) { /* _errorMode = true; */ return e.ErrorCode; }
|
||||
catch(...) { /* _errorMode = true; */ return S_FALSE; }
|
||||
// CNewException is possible here. But probably CNewException is caused
|
||||
// by error in data stream.
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
{
|
||||
if (size < 1)
|
||||
return E_INVALIDARG;
|
||||
_isSolid = ((data[0] & 1) != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,286 @@
|
||||
// Rar3Decoder.h
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
|
||||
|
||||
#ifndef __COMPRESS_RAR3_DECODER_H
|
||||
#define __COMPRESS_RAR3_DECODER_H
|
||||
|
||||
#include "../../../C/Ppmd7.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
|
||||
#include "BitmDecoder.h"
|
||||
#include "HuffmanDecoder.h"
|
||||
#include "Rar3Vm.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NRar3 {
|
||||
|
||||
const UInt32 kWindowSize = 1 << 22;
|
||||
const UInt32 kWindowMask = (kWindowSize - 1);
|
||||
|
||||
const UInt32 kNumReps = 4;
|
||||
const UInt32 kNumLen2Symbols = 8;
|
||||
const UInt32 kLenTableSize = 28;
|
||||
const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize;
|
||||
const UInt32 kDistTableSize = 60;
|
||||
|
||||
const unsigned kNumAlignBits = 4;
|
||||
const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1;
|
||||
|
||||
const UInt32 kLevelTableSize = 20;
|
||||
|
||||
const UInt32 kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize;
|
||||
|
||||
class CBitDecoder
|
||||
{
|
||||
UInt32 _value;
|
||||
unsigned _bitPos;
|
||||
public:
|
||||
CInBuffer Stream;
|
||||
|
||||
bool Create(UInt32 bufSize) { return Stream.Create(bufSize); }
|
||||
void SetStream(ISequentialInStream *inStream) { Stream.SetStream(inStream);}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Stream.Init();
|
||||
_bitPos = 0;
|
||||
_value = 0;
|
||||
}
|
||||
|
||||
bool ExtraBitsWereRead() const
|
||||
{
|
||||
return (Stream.NumExtraBytes > 4 || _bitPos < (Stream.NumExtraBytes << 3));
|
||||
}
|
||||
|
||||
UInt64 GetProcessedSize() const { return Stream.GetProcessedSize() - (_bitPos >> 3); }
|
||||
|
||||
void AlignToByte()
|
||||
{
|
||||
_bitPos &= ~(unsigned)7;
|
||||
_value = _value & ((1 << _bitPos) - 1);
|
||||
}
|
||||
|
||||
UInt32 GetValue(unsigned numBits)
|
||||
{
|
||||
if (_bitPos < numBits)
|
||||
{
|
||||
_bitPos += 8;
|
||||
_value = (_value << 8) | Stream.ReadByte();
|
||||
if (_bitPos < numBits)
|
||||
{
|
||||
_bitPos += 8;
|
||||
_value = (_value << 8) | Stream.ReadByte();
|
||||
}
|
||||
}
|
||||
return _value >> (_bitPos - numBits);
|
||||
}
|
||||
|
||||
void MovePos(unsigned numBits)
|
||||
{
|
||||
_bitPos -= numBits;
|
||||
_value = _value & ((1 << _bitPos) - 1);
|
||||
}
|
||||
|
||||
UInt32 ReadBits(unsigned numBits)
|
||||
{
|
||||
UInt32 res = GetValue(numBits);
|
||||
MovePos(numBits);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
const UInt32 kTopValue = (1 << 24);
|
||||
const UInt32 kBot = (1 << 15);
|
||||
|
||||
struct CRangeDecoder
|
||||
{
|
||||
IPpmd7_RangeDec vt;
|
||||
UInt32 Range;
|
||||
UInt32 Code;
|
||||
UInt32 Low;
|
||||
CBitDecoder BitDecoder;
|
||||
SRes Res;
|
||||
|
||||
public:
|
||||
void InitRangeCoder()
|
||||
{
|
||||
Code = 0;
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for (int i = 0; i < 4; i++)
|
||||
Code = (Code << 8) | BitDecoder.ReadBits(8);
|
||||
}
|
||||
|
||||
void Normalize()
|
||||
{
|
||||
while ((Low ^ (Low + Range)) < kTopValue ||
|
||||
Range < kBot && ((Range = (0 - Low) & (kBot - 1)), 1))
|
||||
{
|
||||
Code = (Code << 8) | BitDecoder.Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
Low <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
CRangeDecoder() throw();
|
||||
};
|
||||
|
||||
struct CFilter: public NVm::CProgram
|
||||
{
|
||||
CRecordVector<Byte> GlobalData;
|
||||
UInt32 BlockStart;
|
||||
UInt32 BlockSize;
|
||||
UInt32 ExecCount;
|
||||
|
||||
CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {}
|
||||
};
|
||||
|
||||
struct CTempFilter: public NVm::CProgramInitState
|
||||
{
|
||||
UInt32 BlockStart;
|
||||
UInt32 BlockSize;
|
||||
bool NextWindow;
|
||||
|
||||
UInt32 FilterIndex;
|
||||
|
||||
CTempFilter()
|
||||
{
|
||||
// all filters must contain at least FixedGlobal block
|
||||
AllocateEmptyFixedGlobal();
|
||||
}
|
||||
};
|
||||
|
||||
const unsigned kNumHuffmanBits = 15;
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetDecoderProperties2,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CRangeDecoder m_InBitStream;
|
||||
Byte *_window;
|
||||
UInt32 _winPos;
|
||||
UInt32 _wrPtr;
|
||||
UInt64 _lzSize;
|
||||
UInt64 _unpackSize;
|
||||
UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written
|
||||
ISequentialOutStream *_outStream;
|
||||
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;
|
||||
|
||||
UInt32 _reps[kNumReps];
|
||||
UInt32 _lastLength;
|
||||
|
||||
Byte m_LastLevels[kTablesSizesSum];
|
||||
|
||||
Byte *_vmData;
|
||||
Byte *_vmCode;
|
||||
NVm::CVm _vm;
|
||||
CRecordVector<CFilter *> _filters;
|
||||
CRecordVector<CTempFilter *> _tempFilters;
|
||||
unsigned _numEmptyTempFilters;
|
||||
UInt32 _lastFilter;
|
||||
|
||||
bool _isSolid;
|
||||
bool _solidAllowed;
|
||||
// bool _errorMode;
|
||||
|
||||
bool _lzMode;
|
||||
bool _unsupportedFilter;
|
||||
|
||||
UInt32 PrevAlignBits;
|
||||
UInt32 PrevAlignCount;
|
||||
|
||||
bool TablesRead;
|
||||
bool TablesOK;
|
||||
|
||||
CPpmd7 _ppmd;
|
||||
int PpmEscChar;
|
||||
bool PpmError;
|
||||
|
||||
HRESULT WriteDataToStream(const Byte *data, UInt32 size);
|
||||
HRESULT WriteData(const Byte *data, UInt32 size);
|
||||
HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr);
|
||||
void ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef);
|
||||
HRESULT WriteBuf();
|
||||
|
||||
void InitFilters();
|
||||
bool AddVmCode(UInt32 firstByte, UInt32 codeSize);
|
||||
bool ReadVmCodeLZ();
|
||||
bool ReadVmCodePPM();
|
||||
|
||||
UInt32 ReadBits(unsigned numBits);
|
||||
|
||||
HRESULT InitPPM();
|
||||
int DecodePpmSymbol();
|
||||
HRESULT DecodePPM(Int32 num, bool &keepDecompressing);
|
||||
|
||||
HRESULT ReadTables(bool &keepDecompressing);
|
||||
HRESULT ReadEndOfBlock(bool &keepDecompressing);
|
||||
HRESULT DecodeLZ(bool &keepDecompressing);
|
||||
HRESULT CodeReal(ICompressProgressInfo *progress);
|
||||
|
||||
bool InputEofError() const { return m_InBitStream.BitDecoder.ExtraBitsWereRead(); }
|
||||
bool InputEofError_Fast() const { return (m_InBitStream.BitDecoder.Stream.NumExtraBytes > 2); }
|
||||
|
||||
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);
|
||||
|
||||
void CopyBlock(UInt32 distance, UInt32 len)
|
||||
{
|
||||
_lzSize += len;
|
||||
UInt32 pos = (_winPos - distance - 1) & kWindowMask;
|
||||
Byte *window = _window;
|
||||
UInt32 winPos = _winPos;
|
||||
if (kWindowSize - winPos > len && kWindowSize - pos > len)
|
||||
{
|
||||
const Byte *src = window + pos;
|
||||
Byte *dest = window + winPos;
|
||||
_winPos += len;
|
||||
do
|
||||
*dest++ = *src++;
|
||||
while (--len != 0);
|
||||
return;
|
||||
}
|
||||
do
|
||||
{
|
||||
window[winPos] = window[pos];
|
||||
winPos = (winPos + 1) & kWindowMask;
|
||||
pos = (pos + 1) & kWindowMask;
|
||||
}
|
||||
while (--len != 0);
|
||||
_winPos = winPos;
|
||||
}
|
||||
|
||||
void PutByte(Byte b)
|
||||
{
|
||||
_window[_winPos] = b;
|
||||
_winPos = (_winPos + 1) & kWindowMask;
|
||||
_lzSize++;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,195 @@
|
||||
// Rar3Vm.h
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
#ifndef __COMPRESS_RAR3_VM_H
|
||||
#define __COMPRESS_RAR3_VM_H
|
||||
|
||||
#include "../../../C/CpuArch.h"
|
||||
|
||||
#include "../../Common/MyVector.h"
|
||||
|
||||
#define RARVM_STANDARD_FILTERS
|
||||
// #define RARVM_VM_ENABLE
|
||||
|
||||
namespace NCompress {
|
||||
namespace NRar3 {
|
||||
|
||||
class CMemBitDecoder
|
||||
{
|
||||
const Byte *_data;
|
||||
UInt32 _bitSize;
|
||||
UInt32 _bitPos;
|
||||
public:
|
||||
void Init(const Byte *data, UInt32 byteSize)
|
||||
{
|
||||
_data = data;
|
||||
_bitSize = (byteSize << 3);
|
||||
_bitPos = 0;
|
||||
}
|
||||
UInt32 ReadBits(unsigned numBits);
|
||||
UInt32 ReadBit();
|
||||
bool Avail() const { return (_bitPos < _bitSize); }
|
||||
|
||||
UInt32 ReadEncodedUInt32();
|
||||
};
|
||||
|
||||
namespace NVm {
|
||||
|
||||
inline UInt32 GetValue32(const void *addr) { return GetUi32(addr); }
|
||||
inline void SetValue32(void *addr, UInt32 value) { SetUi32(addr, value); }
|
||||
|
||||
const unsigned kNumRegBits = 3;
|
||||
const UInt32 kNumRegs = 1 << kNumRegBits;
|
||||
const UInt32 kNumGpRegs = kNumRegs - 1;
|
||||
|
||||
const UInt32 kSpaceSize = 0x40000;
|
||||
const UInt32 kSpaceMask = kSpaceSize - 1;
|
||||
const UInt32 kGlobalOffset = 0x3C000;
|
||||
const UInt32 kGlobalSize = 0x2000;
|
||||
const UInt32 kFixedGlobalSize = 64;
|
||||
|
||||
namespace NGlobalOffset
|
||||
{
|
||||
const UInt32 kBlockSize = 0x1C;
|
||||
const UInt32 kBlockPos = 0x20;
|
||||
const UInt32 kExecCount = 0x2C;
|
||||
const UInt32 kGlobalMemOutSize = 0x30;
|
||||
}
|
||||
|
||||
|
||||
#ifdef RARVM_VM_ENABLE
|
||||
|
||||
enum ECommand
|
||||
{
|
||||
CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC,
|
||||
CMD_JMP, CMD_XOR, CMD_AND, CMD_OR, CMD_TEST, CMD_JS, CMD_JNS, CMD_JB,
|
||||
CMD_JBE, CMD_JA, CMD_JAE, CMD_PUSH, CMD_POP, CMD_CALL, CMD_RET, CMD_NOT,
|
||||
CMD_SHL, CMD_SHR, CMD_SAR, CMD_NEG, CMD_PUSHA,CMD_POPA, CMD_PUSHF,CMD_POPF,
|
||||
CMD_MOVZX,CMD_MOVSX,CMD_XCHG, CMD_MUL, CMD_DIV, CMD_ADC, CMD_SBB, CMD_PRINT,
|
||||
|
||||
CMD_MOVB, CMD_CMPB, CMD_ADDB, CMD_SUBB, CMD_INCB, CMD_DECB,
|
||||
CMD_XORB, CMD_ANDB, CMD_ORB, CMD_TESTB,CMD_NEGB,
|
||||
CMD_SHLB, CMD_SHRB, CMD_SARB, CMD_MULB
|
||||
};
|
||||
|
||||
enum EOpType {OP_TYPE_REG, OP_TYPE_INT, OP_TYPE_REGMEM, OP_TYPE_NONE};
|
||||
|
||||
// Addr in COperand object can link (point) to CVm object!!!
|
||||
|
||||
struct COperand
|
||||
{
|
||||
EOpType Type;
|
||||
UInt32 Data;
|
||||
UInt32 Base;
|
||||
COperand(): Type(OP_TYPE_NONE), Data(0), Base(0) {}
|
||||
};
|
||||
|
||||
struct CCommand
|
||||
{
|
||||
ECommand OpCode;
|
||||
bool ByteMode;
|
||||
COperand Op1, Op2;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
struct CBlockRef
|
||||
{
|
||||
UInt32 Offset;
|
||||
UInt32 Size;
|
||||
};
|
||||
|
||||
|
||||
class CProgram
|
||||
{
|
||||
#ifdef RARVM_VM_ENABLE
|
||||
void ReadProgram(const Byte *code, UInt32 codeSize);
|
||||
public:
|
||||
CRecordVector<CCommand> Commands;
|
||||
#endif
|
||||
|
||||
public:
|
||||
#ifdef RARVM_STANDARD_FILTERS
|
||||
int StandardFilterIndex;
|
||||
#endif
|
||||
|
||||
bool IsSupported;
|
||||
CRecordVector<Byte> StaticData;
|
||||
|
||||
bool PrepareProgram(const Byte *code, UInt32 codeSize);
|
||||
};
|
||||
|
||||
|
||||
struct CProgramInitState
|
||||
{
|
||||
UInt32 InitR[kNumGpRegs];
|
||||
CRecordVector<Byte> GlobalData;
|
||||
|
||||
void AllocateEmptyFixedGlobal()
|
||||
{
|
||||
GlobalData.ClearAndSetSize(NVm::kFixedGlobalSize);
|
||||
memset(&GlobalData[0], 0, NVm::kFixedGlobalSize);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CVm
|
||||
{
|
||||
static UInt32 GetValue(bool byteMode, const void *addr)
|
||||
{
|
||||
if (byteMode)
|
||||
return(*(const Byte *)addr);
|
||||
else
|
||||
return GetUi32(addr);
|
||||
}
|
||||
|
||||
static void SetValue(bool byteMode, void *addr, UInt32 value)
|
||||
{
|
||||
if (byteMode)
|
||||
*(Byte *)addr = (Byte)value;
|
||||
else
|
||||
SetUi32(addr, value);
|
||||
}
|
||||
|
||||
UInt32 GetFixedGlobalValue32(UInt32 globalOffset) { return GetValue(false, &Mem[kGlobalOffset + globalOffset]); }
|
||||
|
||||
void SetBlockSize(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockSize], v); }
|
||||
void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); }
|
||||
public:
|
||||
static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); }
|
||||
|
||||
private:
|
||||
|
||||
#ifdef RARVM_VM_ENABLE
|
||||
UInt32 GetOperand32(const COperand *op) const;
|
||||
void SetOperand32(const COperand *op, UInt32 val);
|
||||
Byte GetOperand8(const COperand *op) const;
|
||||
void SetOperand8(const COperand *op, Byte val);
|
||||
UInt32 GetOperand(bool byteMode, const COperand *op) const;
|
||||
void SetOperand(bool byteMode, const COperand *op, UInt32 val);
|
||||
bool ExecuteCode(const CProgram *prg);
|
||||
#endif
|
||||
|
||||
#ifdef RARVM_STANDARD_FILTERS
|
||||
bool ExecuteStandardFilter(unsigned filterIndex);
|
||||
#endif
|
||||
|
||||
Byte *Mem;
|
||||
UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization)
|
||||
UInt32 Flags;
|
||||
|
||||
public:
|
||||
CVm();
|
||||
~CVm();
|
||||
bool Create();
|
||||
void SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize);
|
||||
bool Execute(CProgram *prg, const CProgramInitState *initState,
|
||||
CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData);
|
||||
const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}}}
|
||||
@@ -0,0 +1,980 @@
|
||||
// Rar5Decoder.cpp
|
||||
// According to unRAR license, this code may not be used to develop
|
||||
// a program that creates RAR archives
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "Rar5Decoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NRar5 {
|
||||
|
||||
static const size_t kInputBufSize = 1 << 20;
|
||||
|
||||
void CBitDecoder::Prepare2() throw()
|
||||
{
|
||||
const unsigned kSize = 16;
|
||||
if (_buf > _bufLim)
|
||||
return;
|
||||
|
||||
size_t rem = _bufLim - _buf;
|
||||
if (rem != 0)
|
||||
memmove(_bufBase, _buf, rem);
|
||||
|
||||
_bufLim = _bufBase + rem;
|
||||
_processedSize += (_buf - _bufBase);
|
||||
_buf = _bufBase;
|
||||
|
||||
if (!_wasFinished)
|
||||
{
|
||||
UInt32 processed = (UInt32)(kInputBufSize - rem);
|
||||
_hres = _stream->Read(_bufLim, (UInt32)processed, &processed);
|
||||
_bufLim += processed;
|
||||
_wasFinished = (processed == 0);
|
||||
if (_hres != S_OK)
|
||||
{
|
||||
_wasFinished = true;
|
||||
// throw CInBufferException(result);
|
||||
}
|
||||
}
|
||||
|
||||
rem = _bufLim - _buf;
|
||||
_bufCheck = _buf;
|
||||
if (rem < kSize)
|
||||
memset(_bufLim, 0xFF, kSize - rem);
|
||||
else
|
||||
_bufCheck = _bufLim - kSize;
|
||||
|
||||
SetCheck2();
|
||||
}
|
||||
|
||||
|
||||
enum FilterType
|
||||
{
|
||||
FILTER_DELTA = 0,
|
||||
FILTER_E8,
|
||||
FILTER_E8E9,
|
||||
FILTER_ARM
|
||||
};
|
||||
|
||||
static const size_t kWriteStep = (size_t)1 << 22;
|
||||
|
||||
CDecoder::CDecoder():
|
||||
_window(NULL),
|
||||
_winPos(0),
|
||||
_winSizeAllocated(0),
|
||||
_lzSize(0),
|
||||
_lzEnd(0),
|
||||
_writtenFileSize(0),
|
||||
_dictSizeLog(0),
|
||||
_isSolid(false),
|
||||
_solidAllowed(false),
|
||||
_wasInit(false),
|
||||
_inputBuf(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder()
|
||||
{
|
||||
::MidFree(_window);
|
||||
::MidFree(_inputBuf);
|
||||
}
|
||||
|
||||
HRESULT CDecoder::WriteData(const Byte *data, size_t size)
|
||||
{
|
||||
HRESULT res = S_OK;
|
||||
if (!_unpackSize_Defined || _writtenFileSize < _unpackSize)
|
||||
{
|
||||
size_t cur = size;
|
||||
if (_unpackSize_Defined)
|
||||
{
|
||||
UInt64 rem = _unpackSize - _writtenFileSize;
|
||||
if (cur > rem)
|
||||
cur = (size_t)rem;
|
||||
}
|
||||
res = WriteStream(_outStream, data, cur);
|
||||
if (res != S_OK)
|
||||
_writeError = true;
|
||||
}
|
||||
_writtenFileSize += size;
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::ExecuteFilter(const CFilter &f)
|
||||
{
|
||||
bool useDest = false;
|
||||
|
||||
Byte *data = _filterSrc;
|
||||
UInt32 dataSize = f.Size;
|
||||
|
||||
// printf("\nType = %d offset = %9d size = %5d", f.Type, (unsigned)(f.Start - _lzFileStart), dataSize);
|
||||
|
||||
switch (f.Type)
|
||||
{
|
||||
case FILTER_E8:
|
||||
case FILTER_E8E9:
|
||||
{
|
||||
// printf(" FILTER_E8");
|
||||
if (dataSize > 4)
|
||||
{
|
||||
dataSize -= 4;
|
||||
UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
|
||||
|
||||
const UInt32 kFileSize = (UInt32)1 << 24;
|
||||
Byte cmpMask = (Byte)(f.Type == FILTER_E8 ? 0xFF : 0xFE);
|
||||
|
||||
for (UInt32 curPos = 0; curPos < dataSize;)
|
||||
{
|
||||
curPos++;
|
||||
if (((*data++) & cmpMask) == 0xE8)
|
||||
{
|
||||
UInt32 offset = (curPos + fileOffset) & (kFileSize - 1);
|
||||
UInt32 addr = GetUi32(data);
|
||||
|
||||
if (addr < kFileSize)
|
||||
{
|
||||
SetUi32(data, addr - offset);
|
||||
}
|
||||
else if (addr > ((UInt32)0xFFFFFFFF - offset)) // (addr > ~(offset))
|
||||
{
|
||||
SetUi32(data, addr + kFileSize);
|
||||
}
|
||||
|
||||
data += 4;
|
||||
curPos += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FILTER_ARM:
|
||||
{
|
||||
if (dataSize >= 4)
|
||||
{
|
||||
dataSize -= 4;
|
||||
UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
|
||||
|
||||
for (UInt32 curPos = 0; curPos <= dataSize; curPos += 4)
|
||||
{
|
||||
Byte *d = data + curPos;
|
||||
if (d[3] == 0xEB)
|
||||
{
|
||||
UInt32 offset = d[0] | ((UInt32)d[1] << 8) | ((UInt32)d[2] << 16);
|
||||
offset -= (fileOffset + curPos) >> 2;
|
||||
d[0] = (Byte)offset;
|
||||
d[1] = (Byte)(offset >> 8);
|
||||
d[2] = (Byte)(offset >> 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FILTER_DELTA:
|
||||
{
|
||||
// printf(" channels = %d", f.Channels);
|
||||
_filterDst.AllocAtLeast(dataSize);
|
||||
if (!_filterDst.IsAllocated())
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
Byte *dest = _filterDst;
|
||||
UInt32 numChannels = f.Channels;
|
||||
|
||||
for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
|
||||
{
|
||||
Byte prevByte = 0;
|
||||
for (UInt32 destPos = curChannel; destPos < dataSize; destPos += numChannels)
|
||||
dest[destPos] = (prevByte = (Byte)(prevByte - *data++));
|
||||
}
|
||||
useDest = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
_unsupportedFilter = true;
|
||||
memset(_filterSrc, 0, f.Size);
|
||||
// return S_OK; // unrar
|
||||
}
|
||||
|
||||
return WriteData(useDest ?
|
||||
(const Byte *)_filterDst :
|
||||
(const Byte *)_filterSrc,
|
||||
f.Size);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::WriteBuf()
|
||||
{
|
||||
DeleteUnusedFilters();
|
||||
|
||||
for (unsigned i = 0; i < _filters.Size();)
|
||||
{
|
||||
const CFilter &f = _filters[i];
|
||||
|
||||
UInt64 blockStart = f.Start;
|
||||
|
||||
size_t lzAvail = (size_t)(_lzSize - _lzWritten);
|
||||
if (lzAvail == 0)
|
||||
break;
|
||||
|
||||
if (blockStart > _lzWritten)
|
||||
{
|
||||
UInt64 rem = blockStart - _lzWritten;
|
||||
size_t size = lzAvail;
|
||||
if (size > rem)
|
||||
size = (size_t)rem;
|
||||
if (size != 0)
|
||||
{
|
||||
RINOK(WriteData(_window + _winPos - lzAvail, size));
|
||||
_lzWritten += size;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
UInt32 blockSize = f.Size;
|
||||
size_t offset = (size_t)(_lzWritten - blockStart);
|
||||
if (offset == 0)
|
||||
{
|
||||
_filterSrc.AllocAtLeast(blockSize);
|
||||
if (!_filterSrc.IsAllocated())
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
size_t blockRem = (size_t)blockSize - offset;
|
||||
size_t size = lzAvail;
|
||||
if (size > blockRem)
|
||||
size = blockRem;
|
||||
memcpy(_filterSrc + offset, _window + _winPos - lzAvail, size);
|
||||
_lzWritten += size;
|
||||
offset += size;
|
||||
if (offset != blockSize)
|
||||
return S_OK;
|
||||
|
||||
_numUnusedFilters = ++i;
|
||||
RINOK(ExecuteFilter(f));
|
||||
}
|
||||
|
||||
DeleteUnusedFilters();
|
||||
|
||||
if (!_filters.IsEmpty())
|
||||
return S_OK;
|
||||
|
||||
size_t lzAvail = (size_t)(_lzSize - _lzWritten);
|
||||
RINOK(WriteData(_window + _winPos - lzAvail, lzAvail));
|
||||
_lzWritten += lzAvail;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
static UInt32 ReadUInt32(CBitDecoder &bi)
|
||||
{
|
||||
unsigned numBytes = bi.ReadBits9fix(2) + 1;
|
||||
UInt32 v = 0;
|
||||
for (unsigned i = 0; i < numBytes; i++)
|
||||
v += ((UInt32)bi.ReadBits9fix(8) << (i * 8));
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
static const unsigned MAX_UNPACK_FILTERS = 8192;
|
||||
|
||||
HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream)
|
||||
{
|
||||
DeleteUnusedFilters();
|
||||
|
||||
if (_filters.Size() >= MAX_UNPACK_FILTERS)
|
||||
{
|
||||
RINOK(WriteBuf());
|
||||
DeleteUnusedFilters();
|
||||
if (_filters.Size() >= MAX_UNPACK_FILTERS)
|
||||
{
|
||||
_unsupportedFilter = true;
|
||||
InitFilters();
|
||||
}
|
||||
}
|
||||
|
||||
_bitStream.Prepare();
|
||||
|
||||
CFilter f;
|
||||
UInt32 blockStart = ReadUInt32(_bitStream);
|
||||
f.Size = ReadUInt32(_bitStream);
|
||||
|
||||
if (f.Size > ((UInt32)1 << 22))
|
||||
{
|
||||
_unsupportedFilter = true;
|
||||
f.Size = 0; // unrar 5.5.5
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (f.Start < _filterEnd)
|
||||
_unsupportedFilter = true;
|
||||
else
|
||||
{
|
||||
_filterEnd = f.Start + f.Size;
|
||||
if (f.Size != 0)
|
||||
_filters.Add(f);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
#define RIF(x) { if (!(x)) return S_FALSE; }
|
||||
|
||||
HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
|
||||
{
|
||||
if (_progress)
|
||||
{
|
||||
const UInt64 packSize = _bitStream.GetProcessedSize();
|
||||
RINOK(_progress->SetRatioInfo(&packSize, &_writtenFileSize));
|
||||
}
|
||||
|
||||
_bitStream.AlignToByte();
|
||||
_bitStream.Prepare();
|
||||
|
||||
{
|
||||
unsigned flags = _bitStream.ReadByteInAligned();
|
||||
unsigned checkSum = _bitStream.ReadByteInAligned();
|
||||
checkSum ^= flags;
|
||||
unsigned num = (flags >> 3) & 3;
|
||||
if (num == 3)
|
||||
return S_FALSE;
|
||||
UInt32 blockSize = _bitStream.ReadByteInAligned();
|
||||
checkSum ^= blockSize;
|
||||
|
||||
if (num != 0)
|
||||
{
|
||||
unsigned b = _bitStream.ReadByteInAligned();
|
||||
checkSum ^= b;
|
||||
blockSize += (UInt32)b << 8;
|
||||
if (num > 1)
|
||||
{
|
||||
b = _bitStream.ReadByteInAligned();
|
||||
checkSum ^= b;
|
||||
blockSize += (UInt32)b << 16;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkSum != 0x5A)
|
||||
return S_FALSE;
|
||||
|
||||
unsigned blockSizeBits7 = (flags & 7) + 1;
|
||||
blockSize += (blockSizeBits7 >> 3);
|
||||
if (blockSize == 0)
|
||||
return S_FALSE;
|
||||
blockSize--;
|
||||
blockSizeBits7 &= 7;
|
||||
|
||||
_bitStream._blockEndBits7 = (Byte)blockSizeBits7;
|
||||
_bitStream._blockEnd = _bitStream.GetProcessedSize_Round() + blockSize;
|
||||
|
||||
_bitStream.SetCheck2();
|
||||
|
||||
_isLastBlock = ((flags & 0x40) != 0);
|
||||
|
||||
if ((flags & 0x80) == 0)
|
||||
{
|
||||
if (!_tableWasFilled)
|
||||
if (blockSize != 0 || blockSizeBits7 != 0)
|
||||
return S_FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_tableWasFilled = false;
|
||||
}
|
||||
|
||||
{
|
||||
Byte lens2[kLevelTableSize];
|
||||
|
||||
for (unsigned i = 0; i < kLevelTableSize;)
|
||||
{
|
||||
_bitStream.Prepare();
|
||||
unsigned len = (unsigned)_bitStream.ReadBits9fix(4);
|
||||
if (len == 15)
|
||||
{
|
||||
unsigned num = (unsigned)_bitStream.ReadBits9fix(4);
|
||||
if (num != 0)
|
||||
{
|
||||
num += 2;
|
||||
num += i;
|
||||
if (num > kLevelTableSize)
|
||||
num = kLevelTableSize;
|
||||
do
|
||||
lens2[i++] = 0;
|
||||
while (i < num);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
lens2[i++] = (Byte)len;
|
||||
}
|
||||
|
||||
if (_bitStream.IsBlockOverRead())
|
||||
return S_FALSE;
|
||||
|
||||
RIF(m_LevelDecoder.Build(lens2));
|
||||
}
|
||||
|
||||
Byte lens[kTablesSizesSum];
|
||||
unsigned i = 0;
|
||||
|
||||
do
|
||||
{
|
||||
if (_bitStream._buf >= _bitStream._bufCheck2)
|
||||
{
|
||||
if (_bitStream._buf >= _bitStream._bufCheck)
|
||||
_bitStream.Prepare();
|
||||
if (_bitStream.IsBlockOverRead())
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
UInt32 sym = m_LevelDecoder.Decode(&_bitStream);
|
||||
|
||||
if (sym < 16)
|
||||
lens[i++] = (Byte)sym;
|
||||
else if (sym > kLevelTableSize)
|
||||
return S_FALSE;
|
||||
else
|
||||
{
|
||||
unsigned num = ((sym - 16) & 1) * 4;
|
||||
num += num + 3 + (unsigned)_bitStream.ReadBits9(num + 3);
|
||||
num += i;
|
||||
if (num > kTablesSizesSum)
|
||||
num = kTablesSizesSum;
|
||||
Byte v = 0;
|
||||
if (sym < 16 + 2)
|
||||
{
|
||||
if (i == 0)
|
||||
return S_FALSE;
|
||||
v = lens[(size_t)i - 1];
|
||||
}
|
||||
do
|
||||
lens[i++] = v;
|
||||
while (i < num);
|
||||
}
|
||||
}
|
||||
while (i < kTablesSizesSum);
|
||||
|
||||
if (_bitStream.IsBlockOverRead())
|
||||
return S_FALSE;
|
||||
if (_bitStream.InputEofError())
|
||||
return S_FALSE;
|
||||
|
||||
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;
|
||||
for (i = 0; i < kAlignTableSize; i++)
|
||||
if (lens[kMainTableSize + kDistTableSize + (size_t)i] != kNumAlignBits)
|
||||
{
|
||||
_useAlignBits = true;
|
||||
break;
|
||||
}
|
||||
|
||||
_tableWasFilled = true;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned SlotToLen(CBitDecoder &_bitStream, unsigned slot)
|
||||
{
|
||||
if (slot < 8)
|
||||
return slot + 2;
|
||||
unsigned numBits = (slot >> 2) - 1;
|
||||
return 2 + ((4 | (slot & 3)) << numBits) + _bitStream.ReadBits9(numBits);
|
||||
}
|
||||
|
||||
|
||||
static const UInt32 kSymbolRep = 258;
|
||||
// static const unsigned kMaxMatchLen = 0x1001 + 3;
|
||||
|
||||
HRESULT CDecoder::DecodeLZ()
|
||||
{
|
||||
CBitDecoder _bitStream;
|
||||
_bitStream._stream = _inStream;
|
||||
_bitStream._bufBase = _inputBuf;
|
||||
_bitStream.Init();
|
||||
|
||||
UInt32 rep0 = _reps[0];
|
||||
|
||||
UInt32 remLen = 0;
|
||||
|
||||
size_t limit;
|
||||
{
|
||||
size_t rem = _winSize - _winPos;
|
||||
if (rem > kWriteStep)
|
||||
rem = kWriteStep;
|
||||
limit = _winPos + rem;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (_winPos >= limit)
|
||||
{
|
||||
RINOK(WriteBuf());
|
||||
if (_unpackSize_Defined && _writtenFileSize > _unpackSize)
|
||||
break; // return S_FALSE;
|
||||
|
||||
{
|
||||
size_t rem = _winSize - _winPos;
|
||||
|
||||
if (rem == 0)
|
||||
{
|
||||
_winPos = 0;
|
||||
rem = _winSize;
|
||||
}
|
||||
if (rem > kWriteStep)
|
||||
rem = kWriteStep;
|
||||
limit = _winPos + rem;
|
||||
}
|
||||
|
||||
if (remLen != 0)
|
||||
{
|
||||
size_t winPos = _winPos;
|
||||
size_t winMask = _winMask;
|
||||
size_t pos = (winPos - (size_t)rep0 - 1) & winMask;
|
||||
|
||||
Byte *win = _window;
|
||||
do
|
||||
{
|
||||
if (winPos >= limit)
|
||||
break;
|
||||
win[winPos] = win[pos];
|
||||
winPos++;
|
||||
pos = (pos + 1) & winMask;
|
||||
}
|
||||
while (--remLen != 0);
|
||||
|
||||
_lzSize += winPos - _winPos;
|
||||
_winPos = winPos;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (_bitStream._buf >= _bitStream._bufCheck2)
|
||||
{
|
||||
if (_bitStream.InputEofError())
|
||||
break; // return S_FALSE;
|
||||
if (_bitStream._buf >= _bitStream._bufCheck)
|
||||
_bitStream.Prepare2();
|
||||
|
||||
UInt64 processed = _bitStream.GetProcessedSize_Round();
|
||||
if (processed >= _bitStream._blockEnd)
|
||||
{
|
||||
if (processed > _bitStream._blockEnd)
|
||||
break; // return S_FALSE;
|
||||
{
|
||||
unsigned bits7 = _bitStream.GetProcessedBits7();
|
||||
if (bits7 > _bitStream._blockEndBits7)
|
||||
break; // return S_FALSE;
|
||||
if (bits7 == _bitStream._blockEndBits7)
|
||||
{
|
||||
if (_isLastBlock)
|
||||
{
|
||||
_reps[0] = rep0;
|
||||
|
||||
if (_bitStream.InputEofError())
|
||||
break;
|
||||
|
||||
/*
|
||||
// packSize can be 15 bytes larger for encrypted archive
|
||||
if (_packSize_Defined && _packSize < _bitStream.GetProcessedSize())
|
||||
break;
|
||||
*/
|
||||
|
||||
return _bitStream._hres;
|
||||
// break;
|
||||
}
|
||||
RINOK(ReadTables(_bitStream));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// that check is not required, but it can help, if there is BUG in another code
|
||||
if (!_tableWasFilled)
|
||||
break; // return S_FALSE;
|
||||
}
|
||||
|
||||
UInt32 sym = m_MainDecoder.Decode(&_bitStream);
|
||||
|
||||
if (sym < 256)
|
||||
{
|
||||
size_t winPos = _winPos;
|
||||
_window[winPos] = (Byte)sym;
|
||||
_winPos = winPos + 1;
|
||||
_lzSize++;
|
||||
continue;
|
||||
}
|
||||
|
||||
UInt32 len;
|
||||
|
||||
if (sym < kSymbolRep + kNumReps)
|
||||
{
|
||||
if (sym >= kSymbolRep)
|
||||
{
|
||||
if (sym != kSymbolRep)
|
||||
{
|
||||
UInt32 dist;
|
||||
if (sym == kSymbolRep + 1)
|
||||
dist = _reps[1];
|
||||
else
|
||||
{
|
||||
if (sym == kSymbolRep + 2)
|
||||
dist = _reps[2];
|
||||
else
|
||||
{
|
||||
dist = _reps[3];
|
||||
_reps[3] = _reps[2];
|
||||
}
|
||||
_reps[2] = _reps[1];
|
||||
}
|
||||
_reps[1] = rep0;
|
||||
rep0 = dist;
|
||||
}
|
||||
|
||||
const UInt32 sym2 = m_LenDecoder.Decode(&_bitStream);
|
||||
if (sym2 >= kLenTableSize)
|
||||
break; // return S_FALSE;
|
||||
len = SlotToLen(_bitStream, sym2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sym == 256)
|
||||
{
|
||||
RINOK(AddFilter(_bitStream));
|
||||
continue;
|
||||
}
|
||||
else // if (sym == 257)
|
||||
{
|
||||
len = _lastLen;
|
||||
// if (len = 0), we ignore that symbol, like original unRAR code, but it can mean error in stream.
|
||||
// if (len == 0) return S_FALSE;
|
||||
if (len == 0)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sym >= kMainTableSize)
|
||||
break; // return S_FALSE;
|
||||
else
|
||||
{
|
||||
_reps[3] = _reps[2];
|
||||
_reps[2] = _reps[1];
|
||||
_reps[1] = rep0;
|
||||
len = SlotToLen(_bitStream, sym - (kSymbolRep + kNumReps));
|
||||
|
||||
rep0 = m_DistDecoder.Decode(&_bitStream);
|
||||
|
||||
if (rep0 >= 4)
|
||||
{
|
||||
if (rep0 >= _numCorrectDistSymbols)
|
||||
break; // return S_FALSE;
|
||||
unsigned numBits = (rep0 >> 1) - 1;
|
||||
rep0 = (2 | (rep0 & 1)) << numBits;
|
||||
|
||||
if (numBits < kNumAlignBits)
|
||||
rep0 += _bitStream.ReadBits9(numBits);
|
||||
else
|
||||
{
|
||||
len += (numBits >= 7);
|
||||
len += (numBits >= 12);
|
||||
len += (numBits >= 17);
|
||||
|
||||
if (_useAlignBits)
|
||||
{
|
||||
// if (numBits > kNumAlignBits)
|
||||
rep0 += (_bitStream.ReadBits32(numBits - kNumAlignBits) << kNumAlignBits);
|
||||
UInt32 a = m_AlignDecoder.Decode(&_bitStream);
|
||||
if (a >= kAlignTableSize)
|
||||
break; // return S_FALSE;
|
||||
rep0 += a;
|
||||
}
|
||||
else
|
||||
rep0 += _bitStream.ReadBits32(numBits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lastLen = len;
|
||||
|
||||
if (rep0 >= _lzSize)
|
||||
_lzError = true;
|
||||
|
||||
{
|
||||
UInt32 lenCur = len;
|
||||
size_t winPos = _winPos;
|
||||
size_t pos = (winPos - (size_t)rep0 - 1) & _winMask;
|
||||
{
|
||||
size_t rem = limit - winPos;
|
||||
// size_t rem = _winSize - winPos;
|
||||
|
||||
if (lenCur > rem)
|
||||
{
|
||||
lenCur = (UInt32)rem;
|
||||
remLen = len - lenCur;
|
||||
}
|
||||
}
|
||||
|
||||
Byte *win = _window;
|
||||
_lzSize += lenCur;
|
||||
_winPos = winPos + lenCur;
|
||||
if (_winSize - pos >= lenCur)
|
||||
{
|
||||
const Byte *src = win + pos;
|
||||
Byte *dest = win + winPos;
|
||||
do
|
||||
*dest++ = *src++;
|
||||
while (--lenCur != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
win[winPos] = win[pos];
|
||||
winPos++;
|
||||
pos = (pos + 1) & _winMask;
|
||||
}
|
||||
while (--lenCur != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_bitStream._hres != S_OK)
|
||||
return _bitStream._hres;
|
||||
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::CodeReal()
|
||||
{
|
||||
_unsupportedFilter = false;
|
||||
_lzError = false;
|
||||
_writeError = false;
|
||||
|
||||
if (!_isSolid || !_wasInit)
|
||||
{
|
||||
size_t clearSize = _winSize;
|
||||
if (_lzSize < _winSize)
|
||||
clearSize = (size_t)_lzSize;
|
||||
memset(_window, 0, clearSize);
|
||||
|
||||
_wasInit = true;
|
||||
_lzSize = 0;
|
||||
_lzWritten = 0;
|
||||
_winPos = 0;
|
||||
|
||||
for (unsigned i = 0; i < kNumReps; i++)
|
||||
_reps[i] = (UInt32)0 - 1;
|
||||
|
||||
_lastLen = 0;
|
||||
_tableWasFilled = false;
|
||||
}
|
||||
|
||||
_isLastBlock = false;
|
||||
|
||||
InitFilters();
|
||||
|
||||
_filterEnd = 0;
|
||||
_writtenFileSize = 0;
|
||||
|
||||
_lzFileStart = _lzSize;
|
||||
_lzWritten = _lzSize;
|
||||
|
||||
HRESULT res = DecodeLZ();
|
||||
|
||||
HRESULT res2 = S_OK;
|
||||
if (!_writeError && res != E_OUTOFMEMORY)
|
||||
res2 = WriteBuf();
|
||||
|
||||
/*
|
||||
if (res == S_OK)
|
||||
if (InputEofError())
|
||||
res = S_FALSE;
|
||||
*/
|
||||
|
||||
if (res == S_OK)
|
||||
{
|
||||
_solidAllowed = true;
|
||||
res = res2;
|
||||
}
|
||||
|
||||
if (res == S_OK && _unpackSize_Defined && _writtenFileSize != _unpackSize)
|
||||
return S_FALSE;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Original unRAR claims that maximum possible filter block size is (1 << 16) now,
|
||||
// and (1 << 17) is minimum win size required to support filter.
|
||||
// Original unRAR uses (1 << 18) for "extra safety and possible filter area size expansion"
|
||||
// We can use any win size.
|
||||
|
||||
static const unsigned kWinSize_Log_Min = 17;
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_isSolid && !_solidAllowed)
|
||||
return S_FALSE;
|
||||
_solidAllowed = false;
|
||||
|
||||
if (_dictSizeLog >= sizeof(size_t) * 8)
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (!_isSolid)
|
||||
_lzEnd = 0;
|
||||
else
|
||||
{
|
||||
if (_lzSize < _lzEnd)
|
||||
{
|
||||
if (_window)
|
||||
{
|
||||
UInt64 rem = _lzEnd - _lzSize;
|
||||
if (rem >= _winSize)
|
||||
memset(_window, 0, _winSize);
|
||||
else
|
||||
{
|
||||
size_t pos = (size_t)_lzSize & _winSize;
|
||||
size_t rem2 = _winSize - pos;
|
||||
if (rem2 > rem)
|
||||
rem2 = (size_t)rem;
|
||||
memset(_window + pos, 0, rem2);
|
||||
rem -= rem2;
|
||||
memset(_window, 0, (size_t)rem);
|
||||
}
|
||||
}
|
||||
_lzEnd &= ((((UInt64)1) << 33) - 1);
|
||||
_lzSize = _lzEnd;
|
||||
_winPos = (size_t)(_lzSize & _winSize);
|
||||
}
|
||||
_lzEnd = _lzSize;
|
||||
}
|
||||
|
||||
size_t newSize;
|
||||
{
|
||||
unsigned newSizeLog = _dictSizeLog;
|
||||
if (newSizeLog < kWinSize_Log_Min)
|
||||
newSizeLog = kWinSize_Log_Min;
|
||||
newSize = (size_t)1 << newSizeLog;
|
||||
_numCorrectDistSymbols = newSizeLog * 2;
|
||||
}
|
||||
|
||||
// If dictionary was reduced, we use allocated dictionary block
|
||||
// for compatibility with original unRAR decoder.
|
||||
|
||||
if (_window && newSize < _winSizeAllocated)
|
||||
_winSize = _winSizeAllocated;
|
||||
else if (!_window || _winSize != newSize)
|
||||
{
|
||||
if (!_isSolid)
|
||||
{
|
||||
::MidFree(_window);
|
||||
_window = NULL;
|
||||
_winSizeAllocated = 0;
|
||||
}
|
||||
|
||||
Byte *win;
|
||||
|
||||
{
|
||||
win = (Byte *)::MidAlloc(newSize);
|
||||
if (!win)
|
||||
return E_OUTOFMEMORY;
|
||||
memset(win, 0, newSize);
|
||||
}
|
||||
|
||||
if (_isSolid && _window)
|
||||
{
|
||||
// original unRAR claims:
|
||||
// "Archiving code guarantees that win size does not grow in the same solid stream",
|
||||
// but the original unRAR decoder still supports such grow case.
|
||||
|
||||
Byte *winOld = _window;
|
||||
size_t oldSize = _winSize;
|
||||
size_t newMask = newSize - 1;
|
||||
size_t oldMask = _winSize - 1;
|
||||
size_t winPos = _winPos;
|
||||
for (size_t i = 1; i <= oldSize; i++)
|
||||
win[(winPos - i) & newMask] = winOld[(winPos - i) & oldMask];
|
||||
::MidFree(_window);
|
||||
}
|
||||
|
||||
_window = win;
|
||||
_winSizeAllocated = newSize;
|
||||
_winSize = newSize;
|
||||
}
|
||||
|
||||
_winMask = _winSize - 1;
|
||||
_winPos &= _winMask;
|
||||
|
||||
if (!_inputBuf)
|
||||
{
|
||||
_inputBuf = (Byte *)::MidAlloc(kInputBufSize);
|
||||
if (!_inputBuf)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
_inStream = inStream;
|
||||
_outStream = outStream;
|
||||
|
||||
/*
|
||||
_packSize = 0;
|
||||
_packSize_Defined = (inSize != NULL);
|
||||
if (_packSize_Defined)
|
||||
_packSize = *inSize;
|
||||
*/
|
||||
|
||||
_unpackSize = 0;
|
||||
_unpackSize_Defined = (outSize != NULL);
|
||||
if (_unpackSize_Defined)
|
||||
_unpackSize = *outSize;
|
||||
|
||||
if ((Int64)_unpackSize >= 0)
|
||||
_lzEnd += _unpackSize;
|
||||
else
|
||||
_lzEnd = 0;
|
||||
|
||||
_progress = progress;
|
||||
|
||||
HRESULT res = CodeReal();
|
||||
|
||||
if (res != S_OK)
|
||||
return res;
|
||||
if (_lzError)
|
||||
return S_FALSE;
|
||||
if (_unsupportedFilter)
|
||||
return E_NOTIMPL;
|
||||
return S_OK;
|
||||
}
|
||||
// catch(const CInBufferException &e) { return e.ErrorCode; }
|
||||
// catch(...) { return S_FALSE; }
|
||||
catch(...) { return E_OUTOFMEMORY; }
|
||||
// CNewException is possible here. But probably CNewException is caused
|
||||
// by error in data stream.
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
||||
{
|
||||
if (size != 2)
|
||||
return E_NOTIMPL;
|
||||
_dictSizeLog = (Byte)((data[0] & 0xF) + 17);
|
||||
_isSolid = ((data[1] & 1) != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,307 @@
|
||||
// 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/CpuArch.h"
|
||||
|
||||
#include "../../Common/MyBuffer2.h"
|
||||
#include "../../Common/MyCom.h"
|
||||
#include "../../Common/MyException.h"
|
||||
#include "../../Common/MyVector.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
#include "HuffmanDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NRar5 {
|
||||
|
||||
|
||||
/*
|
||||
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) const
|
||||
{
|
||||
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;
|
||||
|
||||
bool _isSolid;
|
||||
bool _solidAllowed;
|
||||
bool _tableWasFilled;
|
||||
bool _wasInit;
|
||||
|
||||
Byte _dictSizeLog;
|
||||
|
||||
// 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;
|
||||
|
||||
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
|
||||
@@ -0,0 +1,33 @@
|
||||
// RarCodecsRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/RegisterCodec.h"
|
||||
|
||||
#include "Rar1Decoder.h"
|
||||
#include "Rar2Decoder.h"
|
||||
#include "Rar3Decoder.h"
|
||||
#include "Rar5Decoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
|
||||
#define CREATE_CODEC(x) REGISTER_CODEC_CREATE(CreateCodec ## x, NRar ## x::CDecoder())
|
||||
|
||||
CREATE_CODEC(1)
|
||||
CREATE_CODEC(2)
|
||||
CREATE_CODEC(3)
|
||||
CREATE_CODEC(5)
|
||||
|
||||
#define RAR_CODEC(x, name) { CreateCodec ## x, NULL, 0x40300 + x, "Rar" name, 1, false }
|
||||
|
||||
REGISTER_CODECS_VAR
|
||||
{
|
||||
RAR_CODEC(1, "1"),
|
||||
RAR_CODEC(2, "2"),
|
||||
RAR_CODEC(3, "3"),
|
||||
RAR_CODEC(5, "5"),
|
||||
};
|
||||
|
||||
REGISTER_CODECS(Rar)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
// ShrinkDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
#include "../Common/OutBuffer.h"
|
||||
|
||||
#include "BitlDecoder.h"
|
||||
#include "ShrinkDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NShrink {
|
||||
|
||||
static const UInt32 kEmpty = 256; // kNumItems;
|
||||
static const UInt32 kBufferSize = (1 << 18);
|
||||
static const unsigned kNumMinBits = 9;
|
||||
|
||||
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
NBitl::CBaseDecoder<CInBuffer> inBuffer;
|
||||
COutBuffer outBuffer;
|
||||
|
||||
if (!inBuffer.Create(kBufferSize))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!outBuffer.Create(kBufferSize))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
inBuffer.SetStream(inStream);
|
||||
inBuffer.Init();
|
||||
|
||||
outBuffer.SetStream(outStream);
|
||||
outBuffer.Init();
|
||||
|
||||
{
|
||||
for (unsigned i = 0; i < kNumItems; i++)
|
||||
_parents[i] = kEmpty;
|
||||
}
|
||||
|
||||
UInt64 outPrev = 0, inPrev = 0;
|
||||
unsigned numBits = kNumMinBits;
|
||||
unsigned head = 257;
|
||||
int lastSym = -1;
|
||||
Byte lastChar = 0;
|
||||
bool moreOut = false;
|
||||
|
||||
HRESULT res = S_FALSE;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
_inProcessed = inBuffer.GetProcessedSize();
|
||||
const UInt64 nowPos = outBuffer.GetProcessedSize();
|
||||
|
||||
bool eofCheck = false;
|
||||
|
||||
if (outSize && nowPos >= *outSize)
|
||||
{
|
||||
if (!_fullStreamMode || moreOut)
|
||||
{
|
||||
res = S_OK;
|
||||
break;
|
||||
}
|
||||
eofCheck = true;
|
||||
// Is specSym(=256) allowed after end of stream ?
|
||||
// Do we need to read it here ?
|
||||
}
|
||||
|
||||
if (progress)
|
||||
{
|
||||
if (nowPos - outPrev >= (1 << 20) || _inProcessed - inPrev >= (1 << 20))
|
||||
{
|
||||
outPrev = nowPos;
|
||||
inPrev = _inProcessed;
|
||||
res = progress->SetRatioInfo(&_inProcessed, &nowPos);
|
||||
if (res != SZ_OK)
|
||||
{
|
||||
// break;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 sym = inBuffer.ReadBits(numBits);
|
||||
|
||||
if (inBuffer.ExtraBitsWereRead())
|
||||
{
|
||||
res = S_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sym == 256)
|
||||
{
|
||||
sym = inBuffer.ReadBits(numBits);
|
||||
|
||||
if (inBuffer.ExtraBitsWereRead())
|
||||
break;
|
||||
|
||||
if (sym == 1)
|
||||
{
|
||||
if (numBits >= kNumMaxBits)
|
||||
break;
|
||||
numBits++;
|
||||
continue;
|
||||
}
|
||||
if (sym != 2)
|
||||
{
|
||||
break;
|
||||
// continue; // info-zip just ignores such code
|
||||
}
|
||||
{
|
||||
/*
|
||||
---------- Free leaf nodes ----------
|
||||
Note : that code can mark _parents[lastSym] as free, and next
|
||||
inserted node will be Orphan in that case.
|
||||
*/
|
||||
|
||||
unsigned i;
|
||||
for (i = 256; i < kNumItems; i++)
|
||||
_stack[i] = 0;
|
||||
for (i = 257; i < kNumItems; i++)
|
||||
{
|
||||
unsigned par = _parents[i];
|
||||
if (par != kEmpty)
|
||||
_stack[par] = 1;
|
||||
}
|
||||
for (i = 257; i < kNumItems; i++)
|
||||
if (_stack[i] == 0)
|
||||
_parents[i] = kEmpty;
|
||||
head = 257;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (eofCheck)
|
||||
{
|
||||
// It's can be error case.
|
||||
// That error can be detected later in (*inSize != _inProcessed) check.
|
||||
res = S_OK;
|
||||
break;
|
||||
}
|
||||
|
||||
bool needPrev = false;
|
||||
if (head < kNumItems && lastSym >= 0)
|
||||
{
|
||||
while (head < kNumItems && _parents[head] != kEmpty)
|
||||
head++;
|
||||
if (head < kNumItems)
|
||||
{
|
||||
/*
|
||||
if (head == lastSym), it updates Orphan to self-linked Orphan and creates two problems:
|
||||
1) we must check _stack[i++] overflow in code that walks tree nodes.
|
||||
2) self-linked node can not be removed. So such self-linked nodes can occupy all _parents items.
|
||||
*/
|
||||
needPrev = true;
|
||||
_parents[head] = (UInt16)lastSym;
|
||||
_suffixes[head] = (Byte)lastChar;
|
||||
head++;
|
||||
}
|
||||
}
|
||||
|
||||
lastSym = sym;
|
||||
unsigned cur = sym;
|
||||
unsigned i = 0;
|
||||
|
||||
while (cur >= 256)
|
||||
{
|
||||
_stack[i++] = _suffixes[cur];
|
||||
cur = _parents[cur];
|
||||
// don't change that code:
|
||||
// Orphan Check and self-linked Orphan check (_stack overflow check);
|
||||
if (cur == kEmpty || i >= kNumItems)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur == kEmpty || i >= kNumItems)
|
||||
break;
|
||||
|
||||
_stack[i++] = (Byte)cur;
|
||||
lastChar = (Byte)cur;
|
||||
|
||||
if (needPrev)
|
||||
_suffixes[(size_t)head - 1] = (Byte)cur;
|
||||
|
||||
if (outSize)
|
||||
{
|
||||
const UInt64 limit = *outSize - nowPos;
|
||||
if (i > limit)
|
||||
{
|
||||
moreOut = true;
|
||||
i = (unsigned)limit;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
outBuffer.WriteByte(_stack[--i]);
|
||||
while (i);
|
||||
}
|
||||
|
||||
RINOK(outBuffer.Flush());
|
||||
|
||||
if (res == S_OK)
|
||||
if (_fullStreamMode)
|
||||
{
|
||||
if (moreOut)
|
||||
res = S_FALSE;
|
||||
const UInt64 nowPos = outBuffer.GetProcessedSize();
|
||||
if (outSize && *outSize != nowPos)
|
||||
res = S_FALSE;
|
||||
if (inSize && *inSize != _inProcessed)
|
||||
res = S_FALSE;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
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 COutBufferException &e) { return e.ErrorCode; }
|
||||
catch(const CSystemException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
|
||||
{
|
||||
_fullStreamMode = (finishMode != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
*value = _inProcessed;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,45 @@
|
||||
// ShrinkDecoder.h
|
||||
|
||||
#ifndef __COMPRESS_SHRINK_DECODER_H
|
||||
#define __COMPRESS_SHRINK_DECODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NShrink {
|
||||
|
||||
const unsigned kNumMaxBits = 13;
|
||||
const unsigned kNumItems = 1 << kNumMaxBits;
|
||||
|
||||
class CDecoder :
|
||||
public ICompressCoder,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
bool _fullStreamMode;
|
||||
UInt64 _inProcessed;
|
||||
|
||||
UInt16 _parents[kNumItems];
|
||||
Byte _suffixes[kNumItems];
|
||||
Byte _stack[kNumItems];
|
||||
|
||||
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(
|
||||
ICompressSetFinishMode,
|
||||
ICompressGetInStreamProcessedSize)
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../Common/Common.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
// 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; }
|
||||
|
||||
static const unsigned kNumHuffBits = 15;
|
||||
static const unsigned kNumLenBits = 4;
|
||||
static const unsigned kLenMask = (1 << kNumLenBits) - 1;
|
||||
static const unsigned kNumPosSlots = 16;
|
||||
static const unsigned kNumSyms = 256 + (kNumPosSlots << kNumLenBits);
|
||||
|
||||
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[(size_t)i * 2] = (Byte)(b & 0xF);
|
||||
levels[(size_t)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 >> kNumLenBits;
|
||||
UInt32 len = sym & kLenMask;
|
||||
|
||||
if (len == kLenMask)
|
||||
{
|
||||
if (in > lim)
|
||||
return S_FALSE;
|
||||
len = *in++;
|
||||
if (len == 0xFF)
|
||||
{
|
||||
if (in >= lim)
|
||||
return S_FALSE;
|
||||
len = GetUi16(in);
|
||||
in += 2;
|
||||
}
|
||||
else
|
||||
len += kLenMask;
|
||||
}
|
||||
|
||||
bs.BitPos -= dist;
|
||||
dist = (UInt32)1 << dist;
|
||||
dist += ((bs.Value >> bs.BitPos) & (dist - 1));
|
||||
|
||||
BIT_STREAM_NORMALIZE
|
||||
|
||||
if (len + 3 > 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -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
|
||||
@@ -0,0 +1,150 @@
|
||||
// XzDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
|
||||
#include "XzDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NXz {
|
||||
|
||||
#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \
|
||||
if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes;
|
||||
|
||||
#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
|
||||
if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
|
||||
|
||||
static HRESULT SResToHRESULT_Code(SRes res) throw()
|
||||
{
|
||||
if (res < 0)
|
||||
return res;
|
||||
switch (res)
|
||||
{
|
||||
case SZ_OK: return S_OK;
|
||||
case SZ_ERROR_MEM: return E_OUTOFMEMORY;
|
||||
case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
|
||||
}
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *progress)
|
||||
{
|
||||
MainDecodeSRes = S_OK;
|
||||
MainDecodeSRes_wasUsed = false;
|
||||
XzStatInfo_Clear(&Stat);
|
||||
|
||||
if (!xz)
|
||||
{
|
||||
xz = XzDecMt_Create(&g_Alloc, &g_MidAlloc);
|
||||
if (!xz)
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
CXzDecMtProps props;
|
||||
XzDecMtProps_Init(&props);
|
||||
|
||||
int isMT = False;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
{
|
||||
props.numThreads = 1;
|
||||
UInt32 numThreads = _numThreads;
|
||||
|
||||
if (_tryMt && numThreads > 1)
|
||||
{
|
||||
size_t memUsage = (size_t)_memUsage;
|
||||
if (memUsage != _memUsage)
|
||||
memUsage = (size_t)0 - 1;
|
||||
props.memUseMax = memUsage;
|
||||
isMT = (numThreads > 1);
|
||||
}
|
||||
|
||||
props.numThreads = numThreads;
|
||||
}
|
||||
#endif
|
||||
|
||||
CSeqInStreamWrap inWrap;
|
||||
CSeqOutStreamWrap outWrap;
|
||||
CCompressProgressWrap progressWrap;
|
||||
|
||||
inWrap.Init(seqInStream);
|
||||
outWrap.Init(outStream);
|
||||
progressWrap.Init(progress);
|
||||
|
||||
SRes res = XzDecMt_Decode(xz,
|
||||
&props,
|
||||
outSizeLimit, finishStream,
|
||||
&outWrap.vt,
|
||||
&inWrap.vt,
|
||||
&Stat,
|
||||
&isMT,
|
||||
progress ? &progressWrap.vt : NULL);
|
||||
|
||||
MainDecodeSRes = res;
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
// _tryMt = isMT;
|
||||
#endif
|
||||
|
||||
RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
|
||||
RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
|
||||
RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ)
|
||||
|
||||
// return E_OUTOFMEMORY;
|
||||
|
||||
MainDecodeSRes_wasUsed = true;
|
||||
|
||||
if (res == SZ_OK && finishStream)
|
||||
{
|
||||
/*
|
||||
if (inSize && *inSize != Stat.PhySize)
|
||||
res = SZ_ERROR_DATA;
|
||||
*/
|
||||
if (outSizeLimit && *outSizeLimit != outWrap.Processed)
|
||||
res = SZ_ERROR_DATA;
|
||||
}
|
||||
|
||||
return SResToHRESULT_Code(res);
|
||||
}
|
||||
|
||||
|
||||
HRESULT CComDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
return Decode(inStream, outStream, outSize, _finishStream, progress);
|
||||
}
|
||||
|
||||
STDMETHODIMP CComDecoder::SetFinishMode(UInt32 finishMode)
|
||||
{
|
||||
_finishStream = (finishMode != 0);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CComDecoder::GetInStreamProcessedSize(UInt64 *value)
|
||||
{
|
||||
*value = Stat.InSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
|
||||
STDMETHODIMP CComDecoder::SetNumberOfThreads(UInt32 numThreads)
|
||||
{
|
||||
_numThreads = numThreads;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CComDecoder::SetMemLimit(UInt64 memUsage)
|
||||
{
|
||||
_memUsage = memUsage;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,92 @@
|
||||
// XzDecoder.h
|
||||
|
||||
#ifndef __XZ_DECODER_H
|
||||
#define __XZ_DECODER_H
|
||||
|
||||
#include "../../../C/Xz.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NXz {
|
||||
|
||||
struct CDecoder
|
||||
{
|
||||
CXzDecMtHandle xz;
|
||||
int _tryMt;
|
||||
UInt32 _numThreads;
|
||||
UInt64 _memUsage;
|
||||
|
||||
SRes MainDecodeSRes; // it's not HRESULT
|
||||
bool MainDecodeSRes_wasUsed;
|
||||
CXzStatInfo Stat;
|
||||
|
||||
CDecoder():
|
||||
xz(NULL),
|
||||
_tryMt(True),
|
||||
_numThreads(1),
|
||||
_memUsage((UInt64)(sizeof(size_t)) << 28),
|
||||
MainDecodeSRes(SZ_OK),
|
||||
MainDecodeSRes_wasUsed(false)
|
||||
{}
|
||||
|
||||
~CDecoder()
|
||||
{
|
||||
if (xz)
|
||||
XzDecMt_Destroy(xz);
|
||||
}
|
||||
|
||||
/* Decode() can return ERROR code only if there is progress or stream error.
|
||||
Decode() returns S_OK in case of xz decoding error, but DecodeRes and CStatInfo contain error information */
|
||||
HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *compressProgress);
|
||||
};
|
||||
|
||||
|
||||
class CComDecoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetFinishMode,
|
||||
public ICompressGetInStreamProcessedSize,
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
public ICompressSetCoderMt,
|
||||
public ICompressSetMemLimit,
|
||||
#endif
|
||||
|
||||
public CMyUnknownImp,
|
||||
public CDecoder
|
||||
{
|
||||
bool _finishStream;
|
||||
|
||||
public:
|
||||
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
|
||||
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
|
||||
MY_QUERYINTERFACE_ENTRY(ICompressSetMemLimit)
|
||||
#endif
|
||||
|
||||
MY_QUERYINTERFACE_END
|
||||
MY_ADDREF_RELEASE
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetFinishMode)(UInt32 finishMode);
|
||||
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
|
||||
|
||||
#ifndef _7ZIP_ST
|
||||
STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
|
||||
STDMETHOD(SetMemLimit)(UInt64 memUsage);
|
||||
#endif
|
||||
|
||||
CComDecoder(): _finishStream(false) {}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,245 @@
|
||||
// XzEncoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../../Common/MyString.h"
|
||||
#include "../../Common/StringToInt.h"
|
||||
|
||||
#include "../Common/CWrappers.h"
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "XzEncoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
|
||||
namespace NLzma2 {
|
||||
|
||||
HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props);
|
||||
|
||||
}
|
||||
|
||||
namespace NXz {
|
||||
|
||||
void CEncoder::InitCoderProps()
|
||||
{
|
||||
XzProps_Init(&xzProps);
|
||||
}
|
||||
|
||||
CEncoder::CEncoder()
|
||||
{
|
||||
XzProps_Init(&xzProps);
|
||||
_encoder = NULL;
|
||||
_encoder = XzEnc_Create(&g_Alloc, &g_BigAlloc);
|
||||
if (!_encoder)
|
||||
throw 1;
|
||||
}
|
||||
|
||||
CEncoder::~CEncoder()
|
||||
{
|
||||
if (_encoder)
|
||||
XzEnc_Destroy(_encoder);
|
||||
}
|
||||
|
||||
|
||||
struct CMethodNamePair
|
||||
{
|
||||
UInt32 Id;
|
||||
const char *Name;
|
||||
};
|
||||
|
||||
static const CMethodNamePair g_NamePairs[] =
|
||||
{
|
||||
{ XZ_ID_Delta, "Delta" },
|
||||
{ XZ_ID_X86, "BCJ" },
|
||||
{ XZ_ID_PPC, "PPC" },
|
||||
{ XZ_ID_IA64, "IA64" },
|
||||
{ XZ_ID_ARM, "ARM" },
|
||||
{ XZ_ID_ARMT, "ARMT" },
|
||||
{ XZ_ID_SPARC, "SPARC" }
|
||||
// { XZ_ID_LZMA2, "LZMA2" }
|
||||
};
|
||||
|
||||
static int FilterIdFromName(const wchar_t *name)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++)
|
||||
{
|
||||
const CMethodNamePair &pair = g_NamePairs[i];
|
||||
if (StringsAreEqualNoCase_Ascii(name, pair.Name))
|
||||
return (int)pair.Id;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CEncoder::SetCheckSize(UInt32 checkSizeInBytes)
|
||||
{
|
||||
unsigned id;
|
||||
switch (checkSizeInBytes)
|
||||
{
|
||||
case 0: id = XZ_CHECK_NO; break;
|
||||
case 4: id = XZ_CHECK_CRC32; break;
|
||||
case 8: id = XZ_CHECK_CRC64; break;
|
||||
case 32: id = XZ_CHECK_SHA256; break;
|
||||
default: return E_INVALIDARG;
|
||||
}
|
||||
xzProps.checkId = id;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT CEncoder::SetCoderProp(PROPID propID, const PROPVARIANT &prop)
|
||||
{
|
||||
if (propID == NCoderPropID::kNumThreads)
|
||||
{
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
xzProps.numTotalThreads = (int)(prop.ulVal);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (propID == NCoderPropID::kCheckSize)
|
||||
{
|
||||
if (prop.vt != VT_UI4)
|
||||
return E_INVALIDARG;
|
||||
return SetCheckSize(prop.ulVal);
|
||||
}
|
||||
|
||||
if (propID == NCoderPropID::kBlockSize2)
|
||||
{
|
||||
if (prop.vt == VT_UI4)
|
||||
xzProps.blockSize = prop.ulVal;
|
||||
else if (prop.vt == VT_UI8)
|
||||
xzProps.blockSize = prop.uhVal.QuadPart;
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (propID == NCoderPropID::kReduceSize)
|
||||
{
|
||||
if (prop.vt == VT_UI8)
|
||||
xzProps.reduceSize = prop.uhVal.QuadPart;
|
||||
else
|
||||
return E_INVALIDARG;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (propID == NCoderPropID::kFilter)
|
||||
{
|
||||
if (prop.vt == VT_UI4)
|
||||
{
|
||||
UInt32 id32 = prop.ulVal;
|
||||
if (id32 == XZ_ID_Delta)
|
||||
return E_INVALIDARG;
|
||||
xzProps.filterProps.id = prop.ulVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prop.vt != VT_BSTR)
|
||||
return E_INVALIDARG;
|
||||
|
||||
const wchar_t *name = prop.bstrVal;
|
||||
const wchar_t *end;
|
||||
|
||||
UInt32 id32 = ConvertStringToUInt32(name, &end);
|
||||
|
||||
if (end != name)
|
||||
name = end;
|
||||
else
|
||||
{
|
||||
if (IsString1PrefixedByString2_NoCase_Ascii(name, "Delta"))
|
||||
{
|
||||
name += 5; // strlen("Delta");
|
||||
id32 = XZ_ID_Delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
int filterId = FilterIdFromName(prop.bstrVal);
|
||||
if (filterId < 0 /* || filterId == XZ_ID_LZMA2 */)
|
||||
return E_INVALIDARG;
|
||||
id32 = filterId;
|
||||
}
|
||||
}
|
||||
|
||||
if (id32 == XZ_ID_Delta)
|
||||
{
|
||||
wchar_t c = *name;
|
||||
if (c != '-' && c != ':')
|
||||
return E_INVALIDARG;
|
||||
name++;
|
||||
UInt32 delta = ConvertStringToUInt32(name, &end);
|
||||
if (end == name || *end != 0 || delta == 0 || delta > 256)
|
||||
return E_INVALIDARG;
|
||||
xzProps.filterProps.delta = delta;
|
||||
}
|
||||
|
||||
xzProps.filterProps.id = id32;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return NLzma2::SetLzma2Prop(propID, prop, xzProps.lzma2Props);
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
|
||||
const PROPVARIANT *coderProps, UInt32 numProps)
|
||||
{
|
||||
XzProps_Init(&xzProps);
|
||||
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
RINOK(SetCoderProp(propIDs[i], coderProps[i]));
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
// return SResToHRESULT(XzEnc_SetProps(_encoder, &xzProps));
|
||||
}
|
||||
|
||||
|
||||
STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
|
||||
const PROPVARIANT *coderProps, UInt32 numProps)
|
||||
{
|
||||
for (UInt32 i = 0; i < numProps; i++)
|
||||
{
|
||||
const PROPVARIANT &prop = coderProps[i];
|
||||
PROPID propID = propIDs[i];
|
||||
if (propID == NCoderPropID::kExpectedDataSize)
|
||||
if (prop.vt == VT_UI8)
|
||||
XzEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
|
||||
if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
|
||||
|
||||
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
CSeqInStreamWrap inWrap;
|
||||
CSeqOutStreamWrap outWrap;
|
||||
CCompressProgressWrap progressWrap;
|
||||
|
||||
inWrap.Init(inStream);
|
||||
outWrap.Init(outStream);
|
||||
progressWrap.Init(progress);
|
||||
|
||||
SRes res = XzEnc_SetProps(_encoder, &xzProps);
|
||||
if (res == SZ_OK)
|
||||
res = XzEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, progress ? &progressWrap.vt : NULL);
|
||||
|
||||
// SRes res = Xz_Encode(&outWrap.vt, &inWrap.vt, &xzProps, progress ? &progressWrap.vt : NULL);
|
||||
|
||||
RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
|
||||
RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
|
||||
RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
|
||||
|
||||
return SResToHRESULT(res);
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,46 @@
|
||||
// XzEncoder.h
|
||||
|
||||
#ifndef __XZ_ENCODER_H
|
||||
#define __XZ_ENCODER_H
|
||||
|
||||
#include "../../../C/XzEnc.h"
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NXz {
|
||||
|
||||
|
||||
class CEncoder:
|
||||
public ICompressCoder,
|
||||
public ICompressSetCoderProperties,
|
||||
public ICompressSetCoderPropertiesOpt,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CXzEncHandle _encoder;
|
||||
public:
|
||||
CXzProps xzProps;
|
||||
|
||||
MY_UNKNOWN_IMP3(
|
||||
ICompressCoder,
|
||||
ICompressSetCoderProperties,
|
||||
ICompressSetCoderPropertiesOpt)
|
||||
|
||||
void InitCoderProps();
|
||||
HRESULT SetCheckSize(UInt32 checkSizeInBytes);
|
||||
HRESULT SetCoderProp(PROPID propID, const PROPVARIANT &prop);
|
||||
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
|
||||
|
||||
CEncoder();
|
||||
virtual ~CEncoder();
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,237 @@
|
||||
// ZDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
// #include <stdio.h>
|
||||
|
||||
#include "../../../C/Alloc.h"
|
||||
|
||||
#include "../Common/InBuffer.h"
|
||||
#include "../Common/OutBuffer.h"
|
||||
|
||||
#include "ZDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NZ {
|
||||
|
||||
static const UInt32 kBufferSize = (1 << 20);
|
||||
static const Byte kNumBitsMask = 0x1F;
|
||||
static const Byte kBlockModeMask = 0x80;
|
||||
static const unsigned kNumMinBits = 9;
|
||||
static const unsigned kNumMaxBits = 16;
|
||||
|
||||
void CDecoder::Free()
|
||||
{
|
||||
MyFree(_parents); _parents = 0;
|
||||
MyFree(_suffixes); _suffixes = 0;
|
||||
MyFree(_stack); _stack = 0;
|
||||
}
|
||||
|
||||
CDecoder::~CDecoder() { Free(); }
|
||||
|
||||
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
CInBuffer inBuffer;
|
||||
COutBuffer outBuffer;
|
||||
|
||||
PackSize = 0;
|
||||
|
||||
if (!inBuffer.Create(kBufferSize))
|
||||
return E_OUTOFMEMORY;
|
||||
inBuffer.SetStream(inStream);
|
||||
inBuffer.Init();
|
||||
|
||||
if (!outBuffer.Create(kBufferSize))
|
||||
return E_OUTOFMEMORY;
|
||||
outBuffer.SetStream(outStream);
|
||||
outBuffer.Init();
|
||||
|
||||
Byte buf[kNumMaxBits + 4];
|
||||
{
|
||||
if (inBuffer.ReadBytes(buf, 3) < 3)
|
||||
return S_FALSE;
|
||||
if (buf[0] != 0x1F || buf[1] != 0x9D)
|
||||
return S_FALSE;;
|
||||
}
|
||||
Byte prop = buf[2];
|
||||
|
||||
if ((prop & 0x60) != 0)
|
||||
return S_FALSE;
|
||||
unsigned maxbits = prop & kNumBitsMask;
|
||||
if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
|
||||
return S_FALSE;
|
||||
UInt32 numItems = 1 << maxbits;
|
||||
// Speed optimization: blockSymbol can contain unused velue.
|
||||
|
||||
if (maxbits != _numMaxBits || _parents == 0 || _suffixes == 0 || _stack == 0)
|
||||
{
|
||||
Free();
|
||||
_parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (_parents == 0) return E_OUTOFMEMORY;
|
||||
_suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_suffixes == 0) return E_OUTOFMEMORY;
|
||||
_stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (_stack == 0) return E_OUTOFMEMORY;
|
||||
_numMaxBits = maxbits;
|
||||
}
|
||||
|
||||
UInt64 prevPos = 0;
|
||||
UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits);
|
||||
unsigned numBits = kNumMinBits;
|
||||
UInt32 head = (blockSymbol == 256) ? 257 : 256;
|
||||
bool needPrev = false;
|
||||
unsigned bitPos = 0;
|
||||
unsigned numBufBits = 0;
|
||||
|
||||
_parents[256] = 0; // virus protection
|
||||
_suffixes[256] = 0;
|
||||
HRESULT res = S_OK;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (numBufBits == bitPos)
|
||||
{
|
||||
numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8;
|
||||
bitPos = 0;
|
||||
UInt64 nowPos = outBuffer.GetProcessedSize();
|
||||
if (progress && nowPos - prevPos >= (1 << 13))
|
||||
{
|
||||
prevPos = nowPos;
|
||||
UInt64 packSize = inBuffer.GetProcessedSize();
|
||||
RINOK(progress->SetRatioInfo(&packSize, &nowPos));
|
||||
}
|
||||
}
|
||||
unsigned bytePos = bitPos >> 3;
|
||||
UInt32 symbol = buf[bytePos] | ((UInt32)buf[(size_t)bytePos + 1] << 8) | ((UInt32)buf[(size_t)bytePos + 2] << 16);
|
||||
symbol >>= (bitPos & 7);
|
||||
symbol &= (1 << numBits) - 1;
|
||||
bitPos += numBits;
|
||||
if (bitPos > numBufBits)
|
||||
break;
|
||||
if (symbol >= head)
|
||||
{
|
||||
res = S_FALSE;
|
||||
break;
|
||||
}
|
||||
if (symbol == blockSymbol)
|
||||
{
|
||||
numBufBits = bitPos = 0;
|
||||
numBits = kNumMinBits;
|
||||
head = 257;
|
||||
needPrev = false;
|
||||
continue;
|
||||
}
|
||||
UInt32 cur = symbol;
|
||||
unsigned i = 0;
|
||||
while (cur >= 256)
|
||||
{
|
||||
_stack[i++] = _suffixes[cur];
|
||||
cur = _parents[cur];
|
||||
}
|
||||
_stack[i++] = (Byte)cur;
|
||||
if (needPrev)
|
||||
{
|
||||
_suffixes[(size_t)head - 1] = (Byte)cur;
|
||||
if (symbol == head - 1)
|
||||
_stack[0] = (Byte)cur;
|
||||
}
|
||||
do
|
||||
outBuffer.WriteByte((_stack[--i]));
|
||||
while (i > 0);
|
||||
if (head < numItems)
|
||||
{
|
||||
needPrev = true;
|
||||
_parents[head++] = (UInt16)symbol;
|
||||
if (head > ((UInt32)1 << numBits))
|
||||
{
|
||||
if (numBits < maxbits)
|
||||
{
|
||||
numBufBits = bitPos = 0;
|
||||
numBits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
needPrev = false;
|
||||
}
|
||||
PackSize = inBuffer.GetProcessedSize();
|
||||
HRESULT res2 = outBuffer.Flush();
|
||||
return (res == S_OK) ? res2 : res;
|
||||
}
|
||||
|
||||
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 COutBufferException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
bool CheckStream(const Byte *data, size_t size)
|
||||
{
|
||||
if (size < 3)
|
||||
return false;
|
||||
if (data[0] != 0x1F || data[1] != 0x9D)
|
||||
return false;
|
||||
Byte prop = data[2];
|
||||
if ((prop & 0x60) != 0)
|
||||
return false;
|
||||
unsigned maxbits = prop & kNumBitsMask;
|
||||
if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
|
||||
return false;
|
||||
UInt32 numItems = 1 << maxbits;
|
||||
UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits);
|
||||
unsigned numBits = kNumMinBits;
|
||||
UInt32 head = (blockSymbol == 256) ? 257 : 256;
|
||||
unsigned bitPos = 0;
|
||||
unsigned numBufBits = 0;
|
||||
Byte buf[kNumMaxBits + 4];
|
||||
data += 3;
|
||||
size -= 3;
|
||||
// printf("\n\n");
|
||||
for (;;)
|
||||
{
|
||||
if (numBufBits == bitPos)
|
||||
{
|
||||
unsigned num = (numBits < size) ? numBits : (unsigned)size;
|
||||
memcpy(buf, data, num);
|
||||
data += num;
|
||||
size -= num;
|
||||
numBufBits = num * 8;
|
||||
bitPos = 0;
|
||||
}
|
||||
unsigned bytePos = bitPos >> 3;
|
||||
UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16);
|
||||
symbol >>= (bitPos & 7);
|
||||
symbol &= (1 << numBits) - 1;
|
||||
bitPos += numBits;
|
||||
if (bitPos > numBufBits)
|
||||
{
|
||||
// printf(" OK", symbol);
|
||||
return true;
|
||||
}
|
||||
// printf("%3X ", symbol);
|
||||
if (symbol >= head)
|
||||
return false;
|
||||
if (symbol == blockSymbol)
|
||||
{
|
||||
numBufBits = bitPos = 0;
|
||||
numBits = kNumMinBits;
|
||||
head = 257;
|
||||
continue;
|
||||
}
|
||||
if (head < numItems)
|
||||
{
|
||||
head++;
|
||||
if (head > ((UInt32)1 << numBits))
|
||||
{
|
||||
if (numBits < maxbits)
|
||||
{
|
||||
numBufBits = bitPos = 0;
|
||||
numBits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,54 @@
|
||||
// ZDecoder.h
|
||||
|
||||
#ifndef __COMPRESS_Z_DECODER_H
|
||||
#define __COMPRESS_Z_DECODER_H
|
||||
|
||||
#include "../../Common/MyCom.h"
|
||||
|
||||
#include "../ICoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NZ {
|
||||
|
||||
// Z decoder decodes Z data stream, including 3 bytes of header.
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
UInt16 *_parents;
|
||||
Byte *_suffixes;
|
||||
Byte *_stack;
|
||||
unsigned _numMaxBits;
|
||||
|
||||
public:
|
||||
CDecoder(): _parents(0), _suffixes(0), _stack(0), /* _prop(0), */ _numMaxBits(0) {};
|
||||
~CDecoder();
|
||||
void Free();
|
||||
UInt64 PackSize;
|
||||
|
||||
MY_UNKNOWN_IMP1(ICompressCoder)
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
/*
|
||||
There is no end_of_payload_marker in Z stream.
|
||||
Z decoder stops decoding, if it reaches end of input stream.
|
||||
|
||||
CheckStream function:
|
||||
(size) must be at least 3 bytes (size of Z header).
|
||||
if (size) is larger than size of real Z stream in (data), CheckStream can return false.
|
||||
*/
|
||||
|
||||
const unsigned kRecommendedCheckSize = 64;
|
||||
|
||||
bool CheckStream(const Byte *data, size_t size);
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
// ZlibDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "ZlibDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NZlib {
|
||||
|
||||
#define DEFLATE_TRY_BEGIN try {
|
||||
#define DEFLATE_TRY_END } catch(...) { return S_FALSE; }
|
||||
|
||||
#define ADLER_MOD 65521
|
||||
#define ADLER_LOOP_MAX 5550
|
||||
|
||||
UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size)
|
||||
{
|
||||
UInt32 a = adler & 0xFFFF;
|
||||
UInt32 b = (adler >> 16) & 0xFFFF;
|
||||
while (size > 0)
|
||||
{
|
||||
unsigned curSize = (size > ADLER_LOOP_MAX) ? ADLER_LOOP_MAX : (unsigned )size;
|
||||
unsigned i;
|
||||
for (i = 0; i < curSize; i++)
|
||||
{
|
||||
a += buf[i];
|
||||
b += a;
|
||||
}
|
||||
buf += curSize;
|
||||
size -= curSize;
|
||||
a %= ADLER_MOD;
|
||||
b %= ADLER_MOD;
|
||||
}
|
||||
return (b << 16) + a;
|
||||
}
|
||||
|
||||
STDMETHODIMP COutStreamWithAdler::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
HRESULT result = S_OK;
|
||||
if (_stream)
|
||||
result = _stream->Write(data, size, &size);
|
||||
_adler = Adler32_Update(_adler, (const Byte *)data, size);
|
||||
_size += size;
|
||||
if (processedSize)
|
||||
*processedSize = size;
|
||||
return result;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
DEFLATE_TRY_BEGIN
|
||||
if (!AdlerStream)
|
||||
AdlerStream = AdlerSpec = new COutStreamWithAdler;
|
||||
if (!DeflateDecoder)
|
||||
{
|
||||
DeflateDecoderSpec = new NDeflate::NDecoder::CCOMCoder;
|
||||
DeflateDecoderSpec->ZlibMode = true;
|
||||
DeflateDecoder = DeflateDecoderSpec;
|
||||
}
|
||||
|
||||
if (inSize && *inSize < 2)
|
||||
return S_FALSE;
|
||||
Byte buf[2];
|
||||
RINOK(ReadStream_FALSE(inStream, buf, 2));
|
||||
if (!IsZlib(buf))
|
||||
return S_FALSE;
|
||||
|
||||
AdlerSpec->SetStream(outStream);
|
||||
AdlerSpec->Init();
|
||||
|
||||
UInt64 inSize2 = 0;
|
||||
if (inSize)
|
||||
inSize2 = *inSize - 2;
|
||||
|
||||
HRESULT res = DeflateDecoder->Code(inStream, AdlerStream, inSize ? &inSize2 : NULL, outSize, progress);
|
||||
AdlerSpec->ReleaseStream();
|
||||
|
||||
if (res == S_OK)
|
||||
{
|
||||
const Byte *p = DeflateDecoderSpec->ZlibFooter;
|
||||
UInt32 adler = ((UInt32)p[0] << 24) | ((UInt32)p[1] << 16) | ((UInt32)p[2] << 8) | p[3];
|
||||
if (adler != AdlerSpec->GetAdler())
|
||||
return S_FALSE;
|
||||
}
|
||||
return res;
|
||||
DEFLATE_TRY_END
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,79 @@
|
||||
// ZlibDecoder.h
|
||||
|
||||
#ifndef __ZLIB_DECODER_H
|
||||
#define __ZLIB_DECODER_H
|
||||
|
||||
#include "DeflateDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NZlib {
|
||||
|
||||
const UInt32 ADLER_INIT_VAL = 1;
|
||||
|
||||
class COutStreamWithAdler:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
UInt32 _adler;
|
||||
UInt64 _size;
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void Init() { _adler = ADLER_INIT_VAL; _size = 0; }
|
||||
UInt32 GetAdler() const { return _adler; }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
};
|
||||
|
||||
class CDecoder:
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
COutStreamWithAdler *AdlerSpec;
|
||||
CMyComPtr<ISequentialOutStream> AdlerStream;
|
||||
|
||||
NCompress::NDeflate::NDecoder::CCOMCoder *DeflateDecoderSpec;
|
||||
CMyComPtr<ICompressCoder> DeflateDecoder;
|
||||
public:
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
|
||||
UInt64 GetInputProcessedSize() const { return DeflateDecoderSpec->GetInputProcessedSize() + 2; }
|
||||
UInt64 GetOutputProcessedSize() const { return AdlerSpec->GetSize(); }
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
};
|
||||
|
||||
static bool inline IsZlib(const Byte *p)
|
||||
{
|
||||
if ((p[0] & 0xF) != 8) // method
|
||||
return false;
|
||||
if (((unsigned)p[0] >> 4) > 7) // logar_window_size minus 8.
|
||||
return false;
|
||||
if ((p[1] & 0x20) != 0) // dictPresent
|
||||
return false;
|
||||
if ((((UInt32)p[0] << 8) + p[1]) % 31 != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// IsZlib_3bytes checks 2 bytes of zlib header and starting byte of Deflate stream
|
||||
|
||||
static bool inline IsZlib_3bytes(const Byte *p)
|
||||
{
|
||||
if (!IsZlib(p))
|
||||
return false;
|
||||
unsigned val = p[2];
|
||||
unsigned blockType = (val >> 1) & 0x3;
|
||||
if (blockType == 3) // unsupported block type for deflate
|
||||
return false;
|
||||
if (blockType == NCompress::NDeflate::NBlockType::kStored && (val >> 3) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
// ZlibEncoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../Common/StreamUtils.h"
|
||||
|
||||
#include "ZlibEncoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NZlib {
|
||||
|
||||
#define DEFLATE_TRY_BEGIN try {
|
||||
#define DEFLATE_TRY_END } catch(...) { return S_FALSE; }
|
||||
|
||||
UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size);
|
||||
|
||||
STDMETHODIMP CInStreamWithAdler::Read(void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
HRESULT result = _stream->Read(data, size, &size);
|
||||
_adler = Adler32_Update(_adler, (const Byte *)data, size);
|
||||
_size += size;
|
||||
if (processedSize != NULL)
|
||||
*processedSize = size;
|
||||
return result;
|
||||
}
|
||||
|
||||
void CEncoder::Create()
|
||||
{
|
||||
if (!DeflateEncoder)
|
||||
DeflateEncoder = DeflateEncoderSpec = new NDeflate::NEncoder::CCOMCoder;
|
||||
}
|
||||
|
||||
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
|
||||
{
|
||||
DEFLATE_TRY_BEGIN
|
||||
if (!AdlerStream)
|
||||
AdlerStream = AdlerSpec = new CInStreamWithAdler;
|
||||
Create();
|
||||
|
||||
{
|
||||
Byte buf[2] = { 0x78, 0xDA };
|
||||
RINOK(WriteStream(outStream, buf, 2));
|
||||
}
|
||||
|
||||
AdlerSpec->SetStream(inStream);
|
||||
AdlerSpec->Init();
|
||||
HRESULT res = DeflateEncoder->Code(AdlerStream, outStream, inSize, NULL, progress);
|
||||
AdlerSpec->ReleaseStream();
|
||||
|
||||
RINOK(res);
|
||||
|
||||
{
|
||||
UInt32 a = AdlerSpec->GetAdler();
|
||||
Byte buf[4] = { (Byte)(a >> 24), (Byte)(a >> 16), (Byte)(a >> 8), (Byte)(a) };
|
||||
return WriteStream(outStream, buf, 4);
|
||||
}
|
||||
DEFLATE_TRY_END
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,48 @@
|
||||
// ZlibEncoder.h
|
||||
|
||||
#ifndef __ZLIB_ENCODER_H
|
||||
#define __ZLIB_ENCODER_H
|
||||
|
||||
#include "DeflateEncoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NZlib {
|
||||
|
||||
class CInStreamWithAdler:
|
||||
public ISequentialInStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialInStream> _stream;
|
||||
UInt32 _adler;
|
||||
UInt64 _size;
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
|
||||
void SetStream(ISequentialInStream *stream) { _stream = stream; }
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void Init() { _adler = 1; _size = 0; } // ADLER_INIT_VAL
|
||||
UInt32 GetAdler() const { return _adler; }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
};
|
||||
|
||||
class CEncoder:
|
||||
public ICompressCoder,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CInStreamWithAdler *AdlerSpec;
|
||||
CMyComPtr<ISequentialInStream> AdlerStream;
|
||||
CMyComPtr<ICompressCoder> DeflateEncoder;
|
||||
public:
|
||||
NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec;
|
||||
|
||||
void Create();
|
||||
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
|
||||
UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); }
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user