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:
Simone
2026-04-29 14:07:51 +02:00
commit d074cc7c07
3848 changed files with 1076682 additions and 0 deletions
@@ -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(&currentInPos, &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
+57
View File
@@ -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
+212
View File
@@ -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
+195
View File
@@ -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