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,71 @@
// Compress/BZip2Const.h
#ifndef ZIP7_INC_COMPRESS_BZIP2_CONST_H
#define ZIP7_INC_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 unsigned 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)
lbzip2 2.5: encoder can write up to (18001 + 7) selectors.
7-Zip before 19.03: decoder doesn't support it.
7-Zip 19.03: decoder allows 8 additional selector records for lbzip2 compatibility.
bzip2 1.0.6: decoder can overflow selector[18002] arrays. But there are another
arrays after selector arrays. So the compiled code works.
bzip2 1.0.7: decoder doesn't support it.
bzip2 1.0.8: decoder allows additional selector records for lbzip2 compatibility.
*/
}}
#endif
@@ -0,0 +1,28 @@
// BZip2Crc.cpp
#include "StdAfx.h"
#include "BZip2Crc.h"
MY_ALIGN(64)
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;
}
}
static
class CBZip2CrcTableInit
{
public:
CBZip2CrcTableInit() { CBZip2Crc::InitTable(); }
} g_BZip2CrcTableInit;
@@ -0,0 +1,31 @@
// BZip2Crc.h
#ifndef ZIP7_INC_BZIP2_CRC_H
#define ZIP7_INC_BZIP2_CRC_H
#include "../../Common/MyTypes.h"
class CBZip2Crc
{
UInt32 _value;
static UInt32 Table[256];
public:
static void InitTable();
CBZip2Crc(UInt32 initVal = 0xFFFFFFFF): _value(initVal) {}
void Init(UInt32 initVal = 0xFFFFFFFF) { _value = initVal; }
void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); }
void UpdateByte(unsigned 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,388 @@
// Compress/BZip2Decoder.h
#ifndef ZIP7_INC_COMPRESS_BZIP2_DECODER_H
#define ZIP7_INC_COMPRESS_BZIP2_DECODER_H
#include "../../Common/MyCom.h"
// #define Z7_NO_READ_FROM_CODER
// #define Z7_ST
#ifndef Z7_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;
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);
CBitDecoder():
_buf(NULL),
_lim(NULL)
{
InitBitDecoder();
}
};
// 19.03: we allow additional 8 selectors to support files created by lbzip2.
const UInt32 kNumSelectorsMax_Decoder = kNumSelectorsMax + 8;
struct CBase: public CBitDecoder
{
unsigned numInUse;
UInt32 groupIndex;
UInt32 groupSize;
unsigned runPower;
UInt32 runCounter;
UInt32 blockSize;
UInt32 *Counters;
UInt32 blockSizeMax;
unsigned state;
UInt32 state2;
unsigned state3;
unsigned state4;
unsigned state5;
unsigned numTables;
UInt32 numSelectors;
CBlockProps Props;
private:
CMtf8Decoder mtf;
Byte selectors[kNumSelectorsMax_Decoder];
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 Z7_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,
public ICompressReadUnusedFromInBuf,
#ifndef Z7_NO_READ_FROM_CODER
public ICompressSetInStream,
public ICompressSetOutStreamSize,
public ISequentialInStream,
#endif
#ifndef Z7_ST
public ICompressSetCoderMt,
#endif
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(ICompressCoder)
Z7_COM_QI_ENTRY(ICompressSetFinishMode)
Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf)
#ifndef Z7_NO_READ_FROM_CODER
Z7_COM_QI_ENTRY(ICompressSetInStream)
Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
Z7_COM_QI_ENTRY(ISequentialInStream)
#endif
#ifndef Z7_ST
Z7_COM_QI_ENTRY(ICompressSetCoderMt)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(ICompressCoder)
Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf)
#ifndef Z7_NO_READ_FROM_CODER
Z7_IFACE_COM7_IMP(ICompressSetInStream)
Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
Z7_IFACE_COM7_IMP_NONFINAL(ISequentialInStream)
#endif
public:
#ifndef Z7_ST
Z7_IFACE_COM7_IMP(ICompressSetCoderMt)
#endif
private:
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 Z7_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()
{
// We use InitInputBuffer() before stream init.
// So don't read from stream here
_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 + (size_t)(Base._buf - _inBuf);
}
UInt64 GetInStreamSize() const
{
return _inProcessed + (size_t)(Base._buf - _inBuf) - (Base._numBits >> 3);
}
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);
UInt64 GetNumStreams() const { return Base.NumStreams; }
UInt64 GetNumBlocks() const { return Base.NumBlocks; }
CDecoder();
virtual ~CDecoder();
};
#ifndef Z7_NO_READ_FROM_CODER
class CNsisDecoder Z7_final: public CDecoder
{
Z7_IFACE_COM7_IMP(ISequentialInStream)
};
#endif
}}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,273 @@
// BZip2Encoder.h
#ifndef ZIP7_INC_COMPRESS_BZIP2_ENCODER_H
#define ZIP7_INC_COMPRESS_BZIP2_ENCODER_H
#include "../../Common/MyCom.h"
#ifndef Z7_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 {
const unsigned kNumPassesMax = 10;
struct CMsbfEncoderTemp
{
unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
unsigned _curByte; // low (_bitPos) bits are zeros
// high (8 - _bitPos) bits are filled
Byte *_buf;
Byte *_buf_base;
void SetStream(Byte *buf) { _buf_base = _buf = buf; }
Byte *GetStream() const { return _buf_base; }
void Init()
{
_bitPos = 8;
_curByte = 0;
_buf = _buf_base;
}
// required condition: (value >> numBits) == 0
// numBits == 0 is allowed
void WriteBits(UInt32 value, unsigned numBits)
{
do
{
unsigned bp = _bitPos;
unsigned curByte = _curByte;
if (numBits < bp)
{
bp -= numBits;
_curByte = curByte | (value << bp);
_bitPos = bp;
return;
}
numBits -= bp;
const UInt32 hi = value >> numBits;
value -= (hi << numBits);
Byte *buf = _buf;
_bitPos = 8;
_curByte = 0;
*buf++ = (Byte)(curByte | hi);
_buf = buf;
}
while (numBits);
}
void WriteBit(unsigned value)
{
const unsigned bp = _bitPos - 1;
const unsigned curByte = _curByte | (value << bp);
_curByte = curByte;
_bitPos = bp;
if (bp == 0)
{
*_buf++ = (Byte)curByte;
_curByte = 0;
_bitPos = 8;
}
}
void WriteByte(unsigned b)
{
const unsigned bp = _bitPos;
const unsigned a = _curByte | (b >> (8 - bp));
_curByte = b << bp;
Byte *buf = _buf;
*buf++ = (Byte)a;
_buf = buf;
}
UInt32 GetBytePos() const { return (UInt32)(size_t)(_buf - _buf_base); }
UInt32 GetPos() const { return GetBytePos() * 8 + 8 - _bitPos; }
unsigned GetCurByte() const { return _curByte; }
unsigned GetNonFlushedByteBits() const { return _curByte >> _bitPos; }
void SetPos(UInt32 bitPos)
{
_buf = _buf_base + (bitPos >> 3);
_bitPos = 8 - ((unsigned)bitPos & 7);
}
void SetCurState(unsigned bitPos, unsigned curByte)
{
_bitPos = 8 - bitPos;
_curByte = curByte;
}
};
class CEncoder;
class CThreadInfo
{
private:
CMsbfEncoderTemp m_OutStreamCurrent;
public:
CEncoder *Encoder;
Byte *m_Block;
private:
Byte *m_MtfArray;
Byte *m_TempArray;
UInt32 *m_BlockSorterIndex;
public:
bool m_OptimizeNumTables;
UInt32 m_NumCrcs;
UInt32 m_BlockIndex;
UInt64 m_UnpackSize;
Byte *m_Block_Base;
Byte Lens[kNumTablesMax][kMaxAlphaSize];
UInt32 Freqs[kNumTablesMax][kMaxAlphaSize];
UInt32 Codes[kNumTablesMax][kMaxAlphaSize];
Byte m_Selectors[kNumSelectorsMax];
UInt32 m_CRCs[1 << kNumPassesMax];
void WriteBits2(UInt32 value, unsigned numBits);
void WriteByte2(unsigned b) { WriteBits2(b, 8); }
void WriteBit2(unsigned v) { m_OutStreamCurrent.WriteBit(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:
#ifndef Z7_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;
public:
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
HRESULT Create();
void FinishStream(bool needLeave);
THREAD_FUNC_RET_TYPE ThreadFunc();
#endif
CThreadInfo(): m_BlockSorterIndex(NULL), m_Block_Base(NULL) {}
~CThreadInfo() { Free(); }
bool Alloc();
void Free();
HRESULT EncodeBlock3(UInt32 blockSize);
};
struct CEncProps
{
UInt32 BlockSizeMult;
UInt32 NumPasses;
UInt32 NumThreadGroups;
UInt64 Affinity;
CEncProps()
{
BlockSizeMult = (UInt32)(Int32)-1;
NumPasses = (UInt32)(Int32)-1;
NumThreadGroups = 0;
Affinity = 0;
}
void Normalize(int level);
bool DoOptimizeNumTables() const { return NumPasses > 1; }
};
class CEncoder Z7_final:
public ICompressCoder,
public ICompressSetCoderProperties,
#ifndef Z7_ST
public ICompressSetCoderMt,
#endif
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(ICompressCoder)
Z7_COM_QI_ENTRY(ICompressSetCoderProperties)
#ifndef Z7_ST
Z7_COM_QI_ENTRY(ICompressSetCoderMt)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(ICompressCoder)
Z7_IFACE_COM7_IMP(ICompressSetCoderProperties)
#ifndef Z7_ST
Z7_IFACE_COM7_IMP(ICompressSetCoderMt)
#endif
#ifndef Z7_ST
UInt32 m_NumThreadsPrev;
#endif
public:
CInBuffer m_InStream;
#ifndef Z7_ST
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
#endif
CBitmEncoder<COutBuffer> m_OutStream;
CEncProps _props;
CBZip2CombinedCrc CombinedCrc;
#ifndef Z7_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;
CThreadNextGroup ThreadNextGroup;
HRESULT Result;
ICompressProgressInfo *Progress;
#else
CThreadInfo ThreadsInfo;
#endif
UInt64 NumBlocks;
UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); }
UInt32 ReadRleBlock(Byte *buf);
void WriteBytes(const Byte *data, UInt32 sizeInBits, unsigned lastByteBits);
void WriteByte(Byte b);
#ifndef Z7_ST
HRESULT Create();
void Free();
#endif
public:
CEncoder();
#ifndef Z7_ST
~CEncoder();
#endif
HRESULT Flush() { return m_OutStream.Flush(); }
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
};
}}
#endif
@@ -0,0 +1,25 @@
// BZip2Register.cpp
#include "StdAfx.h"
#include "../Common/RegisterCodec.h"
#include "BZip2Decoder.h"
#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_BZIP2_EXTRACT_ONLY)
#include "BZip2Encoder.h"
#endif
namespace NCompress {
namespace NBZip2 {
REGISTER_CODEC_CREATE(CreateDec, CDecoder)
#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_BZIP2_EXTRACT_ONLY)
REGISTER_CODEC_CREATE(CreateEnc, CEncoder)
#else
#define CreateEnc NULL
#endif
REGISTER_CODEC_2(BZip2, CreateDec, CreateEnc, 0x40202, "BZip2")
}}
@@ -0,0 +1,867 @@
// Bcj2Coder.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../C/Alloc.h"
#include "../Common/StreamUtils.h"
#include "Bcj2Coder.h"
namespace NCompress {
namespace NBcj2 {
CBaseCoder::CBaseCoder()
{
for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
{
_bufs[i] = NULL;
_bufsSizes[i] = 0;
_bufsSizes_New[i] = (1 << 18);
}
}
CBaseCoder::~CBaseCoder()
{
for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
::MidFree(_bufs[i]);
}
HRESULT CBaseCoder::Alloc(bool allocForOrig)
{
const unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS;
for (unsigned i = 0; i < num; i++)
{
UInt32 size = _bufsSizes_New[i];
/* buffer sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP streams
must be aligned for 4 */
size &= ~(UInt32)3;
const UInt32 kMinBufSize = 4;
if (size < kMinBufSize)
size = kMinBufSize;
// size = 4 * 100; // for debug
// if (BCJ2_IS_32BIT_STREAM(i) == 1) size = 4 * 1; // for debug
if (!_bufs[i] || size != _bufsSizes[i])
{
if (_bufs[i])
{
::MidFree(_bufs[i]);
_bufs[i] = NULL;
}
_bufsSizes[i] = 0;
Byte *buf = (Byte *)::MidAlloc(size);
if (!buf)
return E_OUTOFMEMORY;
_bufs[i] = buf;
_bufsSizes[i] = size;
}
}
return S_OK;
}
#ifndef Z7_EXTRACT_ONLY
CEncoder::CEncoder():
_relatLim(BCJ2_ENC_RELAT_LIMIT_DEFAULT)
// , _excludeRangeBits(BCJ2_RELAT_EXCLUDE_NUM_BITS)
{}
CEncoder::~CEncoder() {}
Z7_COM7F_IMF(CEncoder::SetInBufSize(UInt32, UInt32 size))
{ _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; }
Z7_COM7F_IMF(CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size))
{ _bufsSizes_New[streamIndex] = size; return S_OK; }
Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
{
UInt32 relatLim = BCJ2_ENC_RELAT_LIMIT_DEFAULT;
// UInt32 excludeRangeBits = BCJ2_RELAT_EXCLUDE_NUM_BITS;
for (UInt32 i = 0; i < numProps; i++)
{
const PROPVARIANT &prop = props[i];
const PROPID propID = propIDs[i];
if (propID >= NCoderPropID::kReduceSize
// && propID != NCoderPropID::kHashBits
)
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::kHashBits:
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
UInt32 v = prop.ulVal;
if (v > 31)
return E_INVALIDARG;
excludeRangeBits = v;
break;
}
*/
case NCoderPropID::kDictionarySize:
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
relatLim = prop.ulVal;
if (relatLim > BCJ2_ENC_RELAT_LIMIT_MAX)
return E_INVALIDARG;
break;
}
case NCoderPropID::kNumThreads:
case NCoderPropID::kLevel:
continue;
default: return E_INVALIDARG;
}
}
_relatLim = relatLim;
// _excludeRangeBits = excludeRangeBits;
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())
CBcj2Enc_ip_unsigned fileSize_minus1 = BCJ2_ENC_FileSizeField_UNLIMITED;
if (inSizes && inSizes[0])
{
const UInt64 inSize = *inSizes[0];
#ifdef BCJ2_ENC_FileSize_MAX
if (inSize <= BCJ2_ENC_FileSize_MAX)
#endif
fileSize_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(inSize);
}
Z7_DECL_CMyComPtr_QI_FROM(ICompressGetSubStreamSize, getSubStreamSize, inStreams[0])
CBcj2Enc enc;
enc.src = _bufs[BCJ2_NUM_STREAMS];
enc.srcLim = enc.src;
{
for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
{
enc.bufs[i] = _bufs[i];
enc.lims[i] = _bufs[i] + _bufsSizes[i];
}
}
Bcj2Enc_Init(&enc);
enc.fileIp64 = 0;
enc.fileSize64_minus1 = fileSize_minus1;
enc.relatLimit = _relatLim;
// enc.relatExcludeBits = _excludeRangeBits;
enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
// Varibales that correspond processed data in input stream:
UInt64 inPos_without_Temp = 0; // it doesn't include data in enc.temp[]
UInt64 inPos_with_Temp = 0; // it includes data in enc.temp[]
UInt64 prevProgress = 0;
UInt64 totalRead = 0; // size read from input stream
UInt64 outSizeRc = 0;
UInt64 subStream_Index = 0;
UInt64 subStream_StartPos = 0; // global start offset of subStreams[subStream_Index]
UInt64 subStream_Size = 0;
const Byte *srcLim_Read = _bufs[BCJ2_NUM_STREAMS];
bool readWasFinished = false;
bool isAccurate = false;
bool wasUnknownSize = false;
for (;;)
{
if (readWasFinished && enc.srcLim == srcLim_Read)
enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM;
// for debug:
// for (int y=0;y<100;y++) { CBcj2Enc enc2 = enc; Bcj2Enc_Encode(&enc2); }
Bcj2Enc_Encode(&enc);
inPos_with_Temp = totalRead - (size_t)(srcLim_Read - enc.src);
inPos_without_Temp = inPos_with_Temp - Bcj2Enc_Get_AvailInputSize_in_Temp(&enc);
// if (inPos_without_Temp != enc.ip64) return E_FAIL;
if (Bcj2Enc_IsFinished(&enc))
break;
if (enc.state < BCJ2_NUM_STREAMS)
{
if (enc.bufs[enc.state] != enc.lims[enc.state])
return E_FAIL;
const size_t curSize = (size_t)(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] + _bufsSizes[enc.state];
}
else
{
if (enc.state != BCJ2_ENC_STATE_ORIG)
return E_FAIL;
// (enc.state == BCJ2_ENC_STATE_ORIG)
if (enc.src != enc.srcLim)
return E_FAIL;
if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE
&& Bcj2Enc_Get_AvailInputSize_in_Temp(&enc) != 0)
return E_FAIL;
if (enc.src == srcLim_Read)
{
if (readWasFinished)
return E_FAIL;
UInt32 curSize = _bufsSizes[BCJ2_NUM_STREAMS];
RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize))
// printf("Read %6u bytes\n", curSize);
if (curSize == 0)
readWasFinished = true;
totalRead += curSize;
enc.src = _bufs[BCJ2_NUM_STREAMS];
srcLim_Read = _bufs[BCJ2_NUM_STREAMS] + curSize;
}
enc.srcLim = srcLim_Read;
if (getSubStreamSize)
{
/* we set base default conversions options that will be used,
if subStream related options will be not OK */
enc.fileIp64 = 0;
enc.fileSize64_minus1 = fileSize_minus1;
for (;;)
{
UInt64 nextPos;
if (isAccurate)
nextPos = subStream_StartPos + subStream_Size;
else
{
const HRESULT hres = getSubStreamSize->GetSubStreamSize(subStream_Index, &subStream_Size);
if (hres != S_OK)
{
enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
/* if sub-stream size is unknown, we use default settings.
We still can recover to normal mode for next sub-stream,
if GetSubStreamSize() will return S_OK, when current
sub-stream will be finished.
*/
if (hres == S_FALSE)
{
wasUnknownSize = true;
break;
}
if (hres == E_NOTIMPL)
{
getSubStreamSize.Release();
break;
}
return hres;
}
// printf("GetSubStreamSize %6u : %6u \n", (unsigned)subStream_Index, (unsigned)subStream_Size);
nextPos = subStream_StartPos + subStream_Size;
if ((Int64)subStream_Size == -1)
{
/* it's not expected, but (-1) can mean unknown size. */
enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
wasUnknownSize = true;
break;
}
if (nextPos < subStream_StartPos)
return E_FAIL;
isAccurate =
(nextPos < totalRead
|| (nextPos <= totalRead && readWasFinished));
}
/* (nextPos) is estimated end position of current sub_stream.
But only (totalRead) and (readWasFinished) values
can confirm that this estimated end position is accurate.
That end position is accurate, if it can't be changed in
further calls of GetSubStreamSize() */
/* (nextPos < inPos_with_Temp) is unexpected case here, that we
can get if from some incorrect ICompressGetSubStreamSize object,
where new GetSubStreamSize() call returns smaller size than
confirmed by Read() size from previous GetSubStreamSize() call.
*/
if (nextPos < inPos_with_Temp)
{
if (wasUnknownSize)
{
/* that case can be complicated for recovering.
so we disable sub-streams requesting. */
enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
getSubStreamSize.Release();
break;
}
return E_FAIL; // to stop after failure
}
if (nextPos <= inPos_with_Temp)
{
// (nextPos == inPos_with_Temp)
/* CBcj2Enc encoder requires to finish each [non-empty] block (sub-stream)
with BCJ2_ENC_FINISH_MODE_END_BLOCK
or with BCJ2_ENC_FINISH_MODE_END_STREAM for last block:
And we send data of new block to CBcj2Enc, only if previous block was finished.
So we switch to next sub-stream if after Bcj2Enc_Encode() call we have
&& (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE)
&& (nextPos == inPos_with_Temp)
&& (enc.state == BCJ2_ENC_STATE_ORIG)
*/
if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE)
{
/* subStream_StartPos is increased only here.
(subStream_StartPos == inPos_with_Temp) : at start
(subStream_StartPos <= inPos_with_Temp) : will be later
*/
subStream_StartPos = nextPos;
subStream_Size = 0;
wasUnknownSize = false;
subStream_Index++;
isAccurate = false;
// we don't change finishMode here
continue;
}
}
enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
/* for (!isAccurate) case:
(totalRead <= real_end_of_subStream)
so we can use BCJ2_ENC_FINISH_MODE_CONTINUE up to (totalRead)
// we don't change settings at the end of substream, if settings were unknown,
*/
/* if (wasUnknownSize) then we can't trust size of that sub-stream.
so we use default settings instead */
if (!wasUnknownSize)
#ifdef BCJ2_ENC_FileSize_MAX
if (subStream_Size <= BCJ2_ENC_FileSize_MAX)
#endif
{
enc.fileIp64 =
(CBcj2Enc_ip_unsigned)(
(CBcj2Enc_ip_signed)enc.ip64 +
(CBcj2Enc_ip_signed)(subStream_StartPos - inPos_without_Temp));
Bcj2Enc_SET_FileSize(&enc, subStream_Size)
}
if (isAccurate)
{
/* (real_end_of_subStream == nextPos <= totalRead)
So we can use BCJ2_ENC_FINISH_MODE_END_BLOCK up to (nextPos). */
const size_t rem = (size_t)(totalRead - nextPos);
if ((size_t)(enc.srcLim - enc.src) < rem)
return E_FAIL;
enc.srcLim -= rem;
enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK;
}
break;
} // for() loop
} // getSubStreamSize
}
if (progress && inPos_without_Temp - prevProgress >= (1 << 22))
{
prevProgress = inPos_without_Temp;
const UInt64 outSize2 = inPos_without_Temp + outSizeRc +
(size_t)(enc.bufs[BCJ2_STREAM_RC] - _bufs[BCJ2_STREAM_RC]);
// printf("progress %8u, %8u\n", (unsigned)inSize2, (unsigned)outSize2);
RINOK(progress->SetRatioInfo(&inPos_without_Temp, &outSize2))
}
}
for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
{
RINOK(WriteStream(outStreams[i], _bufs[i], (size_t)(enc.bufs[i] - _bufs[i])))
}
// if (inPos_without_Temp != subStream_StartPos + subStream_Size) return E_FAIL;
return S_OK;
}
Z7_COM7F_IMF(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
CDecoder::CDecoder():
_finishMode(false)
#ifndef Z7_NO_READ_FROM_CODER
, _outSizeDefined(false)
, _outSize(0)
, _outSize_Processed(0)
#endif
{}
Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size))
{ _bufsSizes_New[streamIndex] = size; return S_OK; }
Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32, UInt32 size))
{ _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; }
Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
{
_finishMode = (finishMode != 0);
return S_OK;
}
void CBaseDecoder::InitCommon()
{
for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
{
dec.lims[i] = dec.bufs[i] = _bufs[i];
_readRes[i] = S_OK;
_extraSizes[i] = 0;
_readSizes[i] = 0;
}
Bcj2Dec_Init(&dec);
}
/* call ReadInStream() only after Bcj2Dec_Decode().
input requirement:
(dec.state < BCJ2_NUM_STREAMS)
*/
void CBaseDecoder::ReadInStream(ISequentialInStream *inStream)
{
const unsigned state = dec.state;
UInt32 total;
{
Byte *buf = _bufs[state];
const Byte *cur = dec.bufs[state];
// if (cur != dec.lims[state]) throw 1; // unexpected case
dec.lims[state] =
dec.bufs[state] = buf;
total = (UInt32)_extraSizes[state];
for (UInt32 i = 0; i < total; i++)
buf[i] = cur[i];
}
if (_readRes[state] != S_OK)
return;
do
{
UInt32 curSize = _bufsSizes[state] - total;
// if (state == 0) curSize = 0; // for debug
// curSize = 7; // for debug
/* even if we have reached provided inSizes[state] limit,
we call Read() with (curSize != 0), because
we want the called handler of stream->Read() could
execute required Init/Flushing code even for empty stream.
In another way we could call Read() with (curSize == 0) for
finished streams, but some Read() handlers can ignore Read(size=0) calls.
*/
const HRESULT hres = inStream->Read(_bufs[state] + total, curSize, &curSize);
_readRes[state] = hres;
if (curSize == 0)
break;
_readSizes[state] += curSize;
total += curSize;
if (hres != S_OK)
break;
}
while (total < 4 && BCJ2_IS_32BIT_STREAM(state));
/* we exit from decoding loop here, if we can't
provide new data for input stream.
Usually it's normal exit after full stream decoding. */
if (total == 0)
return;
if (BCJ2_IS_32BIT_STREAM(state))
{
const unsigned extra = (unsigned)total & 3;
_extraSizes[state] = extra;
if (total < 4)
{
if (_readRes[state] == S_OK)
_readRes[state] = S_FALSE; // actually it's stream error. So maybe we need another error code.
return;
}
total -= (UInt32)extra;
}
dec.lims[state] += total; // = _bufs[state] + total;
}
Z7_COM7F_IMF(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 outSizeWritten = 0;
UInt64 prevProgress = 0;
HRESULT hres_Crit = S_OK; // critical hres status (mostly from input stream reading)
HRESULT hres_Weak = S_OK; // first non-critical error code from input stream reading
for (;;)
{
if (Bcj2Dec_Decode(&dec) != SZ_OK)
{
/* it's possible only at start (first 5 bytes in RC stream) */
hres_Crit = S_FALSE;
break;
}
if (dec.state < BCJ2_NUM_STREAMS)
{
ReadInStream(inStreams[dec.state]);
const unsigned state = dec.state;
const HRESULT hres = _readRes[state];
if (dec.lims[state] == _bufs[state])
{
// we break decoding, if there are no new data in input stream
hres_Crit = hres;
break;
}
if (hres != S_OK && hres_Weak == S_OK)
hres_Weak = hres;
}
else // (BCJ2_DEC_STATE_ORIG_0 <= state <= BCJ2_STATE_ORIG)
{
{
const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]);
if (curSize != 0)
{
outSizeWritten += curSize;
RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize))
}
}
{
UInt32 rem = _bufsSizes[BCJ2_NUM_STREAMS];
if (outSizes && outSizes[0])
{
const UInt64 outSize = *outSizes[0] - outSizeWritten;
if (rem > outSize)
rem = (UInt32)outSize;
}
dec.dest = _bufs[BCJ2_NUM_STREAMS];
dec.destLim = dec.dest + rem;
/* we exit from decoding loop here,
if (outSizes[0]) limit for output stream was reached */
if (rem == 0)
break;
}
}
if (progress)
{
// here we don't count additional data in dec.temp (up to 4 bytes for output stream)
const UInt64 processed = outSizeWritten + (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]);
if (processed - prevProgress >= (1 << 24))
{
prevProgress = processed;
const UInt64 inSize = processed +
_readSizes[BCJ2_STREAM_RC] - (size_t)(
dec.lims[BCJ2_STREAM_RC] -
dec.bufs[BCJ2_STREAM_RC]);
RINOK(progress->SetRatioInfo(&inSize, &prevProgress))
}
}
}
{
const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]);
if (curSize != 0)
{
outSizeWritten += curSize;
RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize))
}
}
if (hres_Crit == S_OK) hres_Crit = hres_Weak;
if (hres_Crit != S_OK) return hres_Crit;
if (_finishMode)
{
if (!Bcj2Dec_IsMaybeFinished_code(&dec))
return S_FALSE;
/* here we support two correct ways to finish full stream decoding
with one of the following conditions:
- the end of input stream MAIN was reached
- the end of output stream ORIG was reached
Currently 7-Zip/7z code ends with (state == BCJ2_STREAM_MAIN),
because the sizes of MAIN and ORIG streams are known and these
sizes are stored in 7z archive headers.
And Bcj2Dec_Decode() exits with (state == BCJ2_STREAM_MAIN),
if both MAIN and ORIG streams have reached buffers limits.
But if the size of MAIN stream is not known or if the
size of MAIN stream includes some padding after payload data,
then we still can correctly finish decoding with
(state == BCJ2_DEC_STATE_ORIG), if we know the exact size
of output ORIG stream.
*/
if (dec.state != BCJ2_STREAM_MAIN)
if (dec.state != BCJ2_DEC_STATE_ORIG)
return S_FALSE;
/* the caller also will know written size.
So the following check is optional: */
if (outSizes && outSizes[0] && *outSizes[0] != outSizeWritten)
return S_FALSE;
if (inSizes)
{
for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
{
/* if (inSizes[i]) is defined, we do full check for processed stream size. */
if (inSizes[i] && *inSizes[i] != GetProcessedSize_ForInStream(i))
return S_FALSE;
}
}
/* v23.02: we call Read(0) for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP streams,
if there were no Read() calls for such stream.
So the handlers of these input streams objects can do
Init/Flushing even for case when stream is empty:
*/
for (unsigned i = BCJ2_STREAM_CALL; i < BCJ2_STREAM_CALL + 2; i++)
{
if (_readSizes[i])
continue;
Byte b;
UInt32 processed;
RINOK(inStreams[i]->Read(&b, 0, &processed))
}
}
return S_OK;
}
Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value))
{
*value = GetProcessedSize_ForInStream(streamIndex);
return S_OK;
}
#ifndef Z7_NO_READ_FROM_CODER
Z7_COM7F_IMF(CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream))
{
_inStreams[streamIndex] = inStream;
return S_OK;
}
Z7_COM7F_IMF(CDecoder::ReleaseInStream2(UInt32 streamIndex))
{
_inStreams[streamIndex].Release();
return S_OK;
}
Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
{
_outSizeDefined = (outSize != NULL);
_outSize = 0;
if (_outSizeDefined)
_outSize = *outSize;
_outSize_Processed = 0;
const HRESULT res = Alloc(false); // allocForOrig
InitCommon();
dec.destLim = dec.dest = NULL;
return res;
}
Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
/* Note the case:
The output (ORIG) stream can be empty.
But BCJ2_STREAM_RC stream always is not empty.
And we want to support full data processing for all streams.
We disable check (size == 0) here.
So if the caller calls this CDecoder::Read() with (size == 0),
we execute required Init/Flushing code in this CDecoder object.
Also this CDecoder::Read() function will call Read() for input streams.
So the handlers of input streams objects also can do Init/Flushing.
*/
// if (size == 0) return S_OK; // disabled to allow (size == 0) processing
UInt32 totalProcessed = 0;
if (_outSizeDefined)
{
const 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 (;;)
{
if (Bcj2Dec_Decode(&dec) != SZ_OK)
return S_FALSE; // this error can be only at start of stream
{
const UInt32 curSize = (UInt32)(size_t)(dec.dest - (Byte *)data);
if (curSize != 0)
{
data = (void *)((Byte *)data + curSize);
size -= curSize;
_outSize_Processed += curSize;
totalProcessed += curSize;
if (processedSize)
*processedSize = totalProcessed;
}
}
if (dec.state >= BCJ2_NUM_STREAMS)
break;
ReadInStream(_inStreams[dec.state]);
if (dec.lims[dec.state] == _bufs[dec.state])
{
/* we break decoding, if there are no new data in input stream.
and we ignore error code, if some data were written to output buffer. */
if (totalProcessed == 0)
res = _readRes[dec.state];
break;
}
}
if (res == S_OK)
if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed)
{
if (!Bcj2Dec_IsMaybeFinished_code(&dec))
return S_FALSE;
if (dec.state != BCJ2_STREAM_MAIN)
if (dec.state != BCJ2_DEC_STATE_ORIG)
return S_FALSE;
}
return res;
}
#endif
}}
/*
extern "C"
{
extern UInt32 bcj2_stats[256 + 2][2];
}
static class CBcj2Stat
{
public:
~CBcj2Stat()
{
printf("\nBCJ2 stat:");
unsigned sums[2] = { 0, 0 };
int i;
for (i = 2; i < 256 + 2; i++)
{
sums[0] += bcj2_stats[i][0];
sums[1] += bcj2_stats[i][1];
}
const unsigned sums2 = sums[0] + sums[1];
for (int vi = 0; vi < 256 + 3; vi++)
{
printf("\n");
UInt32 n0, n1;
if (vi < 4)
printf("\n");
if (vi < 2)
i = vi;
else if (vi == 2)
i = -1;
else
i = vi - 1;
if (i < 0)
{
n0 = sums[0];
n1 = sums[1];
printf("calls :");
}
else
{
if (i == 0)
printf("jcc :");
else if (i == 1)
printf("jump :");
else
printf("call %02x :", i - 2);
n0 = bcj2_stats[i][0];
n1 = bcj2_stats[i][1];
}
const UInt32 sum = n0 + n1;
printf(" %10u", sum);
#define PRINT_PERC(val, sum) \
{ UInt32 _sum = sum; if (_sum == 0) _sum = 1; \
printf(" %7.3f %%", (double)((double)val * (double)100 / (double)_sum )); }
if (i >= 2 || i < 0)
{
PRINT_PERC(sum, sums2);
}
else
printf("%10s", "");
printf(" :%10u", n0);
PRINT_PERC(n0, sum);
printf(" :%10u", n1);
PRINT_PERC(n1, sum);
}
printf("\n\n");
fflush(stdout);
}
} g_CBcjStat;
*/
@@ -0,0 +1,127 @@
// Bcj2Coder.h
#ifndef ZIP7_INC_COMPRESS_BCJ2_CODER_H
#define ZIP7_INC_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 _bufsSizes[BCJ2_NUM_STREAMS + 1];
UInt32 _bufsSizes_New[BCJ2_NUM_STREAMS + 1];
HRESULT Alloc(bool allocForOrig = true);
public:
CBaseCoder();
~CBaseCoder();
};
#ifndef Z7_EXTRACT_ONLY
class CEncoder Z7_final:
public ICompressCoder2,
public ICompressSetCoderProperties,
public ICompressSetBufSize,
public CMyUnknownImp,
public CBaseCoder
{
Z7_IFACES_IMP_UNK_3(
ICompressCoder2,
ICompressSetCoderProperties,
ICompressSetBufSize)
UInt32 _relatLim;
// UInt32 _excludeRangeBits;
HRESULT CodeReal(
ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
ICompressProgressInfo *progress);
public:
CEncoder();
~CEncoder();
};
#endif
class CBaseDecoder: public CBaseCoder
{
protected:
HRESULT _readRes[BCJ2_NUM_STREAMS];
unsigned _extraSizes[BCJ2_NUM_STREAMS];
UInt64 _readSizes[BCJ2_NUM_STREAMS];
CBcj2Dec dec;
UInt64 GetProcessedSize_ForInStream(unsigned i) const
{
return _readSizes[i] - ((size_t)(dec.lims[i] - dec.bufs[i]) + _extraSizes[i]);
}
void InitCommon();
void ReadInStream(ISequentialInStream *inStream);
};
class CDecoder Z7_final:
public ICompressCoder2,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize2,
public ICompressSetBufSize,
#ifndef Z7_NO_READ_FROM_CODER
public ICompressSetInStream2,
public ICompressSetOutStreamSize,
public ISequentialInStream,
#endif
public CMyUnknownImp,
public CBaseDecoder
{
Z7_COM_QI_BEGIN2(ICompressCoder2)
Z7_COM_QI_ENTRY(ICompressSetFinishMode)
Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize2)
Z7_COM_QI_ENTRY(ICompressSetBufSize)
#ifndef Z7_NO_READ_FROM_CODER
Z7_COM_QI_ENTRY(ICompressSetInStream2)
Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
Z7_COM_QI_ENTRY(ISequentialInStream)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(ICompressCoder2)
Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize2)
Z7_IFACE_COM7_IMP(ICompressSetBufSize)
#ifndef Z7_NO_READ_FROM_CODER
Z7_IFACE_COM7_IMP(ICompressSetInStream2)
Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
Z7_IFACE_COM7_IMP(ISequentialInStream)
#endif
bool _finishMode;
#ifndef Z7_NO_READ_FROM_CODER
bool _outSizeDefined;
UInt64 _outSize;
UInt64 _outSize_Processed;
CMyComPtr<ISequentialInStream> _inStreams[BCJ2_NUM_STREAMS];
#endif
public:
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 Z7_EXTRACT_ONLY
REGISTER_CODEC_CREATE_2(CreateCodecOut, CEncoder(), ICompressCoder2)
#else
#define CreateCodecOut NULL
#endif
REGISTER_CODEC_VAR(BCJ2)
{ 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 {
Z7_COM7F_IMF(CCoder2::Init())
{
_pc = 0;
_state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
return S_OK;
}
Z7_COM7F_IMF2(UInt32, CCoder2::Filter(Byte *data, UInt32 size))
{
const UInt32 processed = (UInt32)(size_t)(_convFunc(data, size, _pc, &_state) - data);
_pc += processed;
return processed;
}
}}
@@ -0,0 +1,37 @@
// BcjCoder.h
#ifndef ZIP7_INC_COMPRESS_BCJ_CODER_H
#define ZIP7_INC_COMPRESS_BCJ_CODER_H
#include "../../../C/Bra.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
namespace NBcj {
/* CCoder in old versions used another constructor parameter CCoder(int encode).
And some code called it as CCoder(0).
We have changed constructor parameter type.
So we have changed the name of class also to CCoder2. */
Z7_CLASS_IMP_COM_1(
CCoder2
, ICompressFilter
)
UInt32 _pc;
UInt32 _state;
z7_Func_BranchConvSt _convFunc;
public:
CCoder2(z7_Func_BranchConvSt convFunc):
_pc(0),
_state(Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL),
_convFunc(convFunc)
{}
};
}}
#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,
CCoder2(z7_BranchConvSt_X86_Dec),
CCoder2(z7_BranchConvSt_X86_Enc),
0x3030103, "BCJ")
}}
@@ -0,0 +1,32 @@
// BitlDecoder.cpp
#include "StdAfx.h"
#include "BitlDecoder.h"
namespace NBitl {
#if defined(Z7_BITL_USE_REVERSE_BITS_TABLE)
MY_ALIGN(64)
Byte kReverseTable[256];
static
struct CReverseerTableInitializer
{
CReverseerTableInitializer()
{
for (unsigned i = 0; i < 256; i++)
{
unsigned
x = ((i & 0x55) << 1) | ((i >> 1) & 0x55);
x = ((x & 0x33) << 2) | ((x >> 2) & 0x33);
kReverseTable[i] = (Byte)((x << 4) | (x >> 4));
}
}
} g_ReverseerTableInitializer;
#elif 0
unsigned ReverseBits8test(unsigned i) { return ReverseBits8(i); }
#endif
}
@@ -0,0 +1,225 @@
// BitlDecoder.h -- the Least Significant Bit of byte is First
#ifndef ZIP7_INC_BITL_DECODER_H
#define ZIP7_INC_BITL_DECODER_H
#include "../../../C/CpuArch.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;
#if !defined(Z7_BITL_USE_REVERSE_BITS_TABLE)
#if 1 && defined(MY_CPU_ARM_OR_ARM64) \
&& (defined(MY_CPU_ARM64) || defined(__ARM_ARCH_6T2__) \
|| defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) \
&& (defined(__GNUC__) && (__GNUC__ >= 4) \
|| defined(__clang__) && (__clang_major__ >= 4))
#define Z7_BITL_USE_REVERSE_BITS_INSTRUCTION
#elif 1
#define Z7_BITL_USE_REVERSE_BITS_TABLE
#endif
#endif
#if defined(Z7_BITL_USE_REVERSE_BITS_TABLE)
extern Byte kReverseTable[256];
#endif
inline unsigned ReverseBits8(unsigned i)
{
#if defined(Z7_BITL_USE_REVERSE_BITS_TABLE)
return kReverseTable[i];
#elif defined(Z7_BITL_USE_REVERSE_BITS_INSTRUCTION)
// rbit is available in ARMv6T2 and above
asm ("rbit "
#if defined(MY_CPU_ARM)
"%0,%0" // it uses default register size,
// but we need 32-bit register here.
// we must use it only if default register size is 32-bit.
// it will work incorrectly for ARM64.
#else
"%w0,%w0" // it uses 32-bit registers in ARM64.
// compiler for (MY_CPU_ARM) can't compile it.
#endif
: "+r" (i));
return i >> 24;
#else
unsigned
x = ((i & 0x55) << 1) | ((i >> 1) & 0x55);
x = ((x & 0x33) << 2) | ((x >> 2) & 0x33);
return ((x & 0x0f) << 4) | (x >> 4);
#endif
}
/* 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 ClearStreamPtr() { _stream.ClearStreamPtr(); }
void Init()
{
_stream.Init();
_bitPos = kNumBigValueBits;
_value = 0;
}
// the size of portion data in real stream that was already read from this object.
// it doesn't include unused data in BitStream object buffer (up to 4 bytes)
// it doesn't include unused data in TInByte buffers
// it doesn't include virtual Extra bytes after the end of real stream data
UInt64 GetStreamSize() const
{
return ExtraBitsWereRead() ?
_stream.GetStreamSize():
GetProcessedSize();
}
// the size of virtual data that was read from this object.
UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); }
bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; }
Z7_FORCE_INLINE
void Normalize()
{
for (; _bitPos >= 8; _bitPos -= 8)
_value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value;
}
Z7_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;
}
Z7_FORCE_INLINE
void Normalize()
{
for (; this->_bitPos >= 8; this->_bitPos -= 8)
{
const unsigned b = this->_stream.ReadByte();
_normalValue = ((UInt32)b << (kNumBigValueBits - this->_bitPos)) | _normalValue;
this->_value = (this->_value << 8) | ReverseBits8(b);
}
}
Z7_FORCE_INLINE
UInt32 GetValue(unsigned numBits)
{
Normalize();
return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits);
}
Z7_FORCE_INLINE
UInt32 GetValue_InHigh32bits()
{
Normalize();
return this->_value << this->_bitPos;
}
Z7_FORCE_INLINE
void MovePos(size_t numBits)
{
this->_bitPos += (unsigned)numBits;
_normalValue >>= numBits;
}
Z7_FORCE_INLINE
UInt32 ReadBits(unsigned numBits)
{
Normalize();
UInt32 res = _normalValue & ((1 << numBits) - 1);
MovePos(numBits);
return res;
}
void AlignToByte() { MovePos((32 - this->_bitPos) & 7); }
Z7_FORCE_INLINE
Byte ReadDirectByte() { return this->_stream.ReadByte(); }
Z7_FORCE_INLINE
size_t ReadDirectBytesPart(Byte *buf, size_t size) { return this->_stream.ReadBytesPart(buf, size); }
Z7_FORCE_INLINE
Byte ReadAlignedByte()
{
if (this->_bitPos == kNumBigValueBits)
return this->_stream.ReadByte();
Byte b = (Byte)(_normalValue & 0xFF);
MovePos(8);
return b;
}
// call it only if the object is aligned for byte.
Z7_FORCE_INLINE
bool ReadAlignedByte_FromBuf(Byte &b)
{
if (this->_stream.NumExtraBytes != 0)
if (this->_stream.NumExtraBytes >= 4
|| kNumBigValueBits - this->_bitPos <= (this->_stream.NumExtraBytes << 3))
return false;
if (this->_bitPos == kNumBigValueBits)
return this->_stream.ReadByte_FromBuf(b);
b = (Byte)(_normalValue & 0xFF);
MovePos(8);
return true;
}
};
}
#endif
@@ -0,0 +1,57 @@
// BitlEncoder.h -- the Least Significant Bit of byte is First
#ifndef ZIP7_INC_BITL_ENCODER_H
#define ZIP7_INC_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;
}
Z7_FORCE_INLINE
void WriteBits(UInt32 value, unsigned numBits)
{
while (numBits > 0)
{
if (numBits < _bitPos)
{
_curByte |= (Byte)((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,106 @@
// BitmDecoder.h -- the Most Significant Bit of byte is First
#ifndef ZIP7_INC_BITM_DECODER_H
#define ZIP7_INC_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);
}
Z7_FORCE_INLINE
void Normalize()
{
for (; _bitPos >= 8; _bitPos -= 8)
_value = (_value << 8) | _stream.ReadByte();
}
Z7_FORCE_INLINE
UInt32 GetValue(unsigned numBits) const
{
// return (_value << _bitPos) >> (kNumBigValueBits - numBits);
return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits);
}
Z7_FORCE_INLINE
UInt32 GetValue_InHigh32bits() const
{
return this->_value << this->_bitPos;
}
Z7_FORCE_INLINE
void MovePos(unsigned numBits)
{
_bitPos += numBits;
Normalize();
}
Z7_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); }
Z7_FORCE_INLINE
UInt32 ReadAlignBits() { return ReadBits((kNumBigValueBits - _bitPos) & 7); }
};
}
#endif
@@ -0,0 +1,90 @@
// BitmEncoder.h -- the Most Significant Bit of byte is First
#ifndef ZIP7_INC_BITM_ENCODER_H
#define ZIP7_INC_BITM_ENCODER_H
#include "../IStream.h"
template<class TOutByte>
class CBitmEncoder
{
unsigned _bitPos; // 0 < _bitPos <= 8 : number of non-filled low bits in _curByte
unsigned _curByte; // low (_bitPos) bits are zeros
// high (8 - _bitPos) bits are filled
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)
{
_stream.WriteByte((Byte)_curByte);
_bitPos = 8;
_curByte = 0;
}
return _stream.Flush();
}
// required condition: (value >> numBits) == 0
// numBits == 0 is allowed
void WriteBits(UInt32 value, unsigned numBits)
{
do
{
unsigned bp = _bitPos;
unsigned curByte = _curByte;
if (numBits < bp)
{
bp -= numBits;
_curByte = curByte | (value << bp);
_bitPos = bp;
return;
}
numBits -= bp;
const UInt32 hi = (value >> numBits);
value -= (hi << numBits);
_stream.WriteByte((Byte)(curByte | hi));
_bitPos = 8;
_curByte = 0;
}
while (numBits);
}
void WriteByte(unsigned b)
{
const unsigned bp = _bitPos;
const unsigned a = _curByte | (b >> (8 - bp));
_curByte = b << bp;
_stream.WriteByte((Byte)a);
}
void WriteBytes(const Byte *data, size_t num)
{
const unsigned bp = _bitPos;
#if 1 // 1 for optional speed-optimized code branch
if (bp == 8)
{
_stream.WriteBytes(data, num);
return;
}
#endif
unsigned c = _curByte;
const unsigned bp_rev = 8 - bp;
for (size_t i = 0; i < num; i++)
{
const unsigned b = data[i];
_stream.WriteByte((Byte)(c | (b >> bp_rev)));
c = b << bp;
}
_curByte = c;
}
};
#endif
@@ -0,0 +1,106 @@
// BranchMisc.cpp
#include "StdAfx.h"
#include "../../../C/CpuArch.h"
#include "../Common/StreamUtils.h"
#include "BranchMisc.h"
namespace NCompress {
namespace NBranch {
Z7_COM7F_IMF(CCoder::Init())
{
_pc = 0;
return S_OK;
}
Z7_COM7F_IMF2(UInt32, CCoder::Filter(Byte *data, UInt32 size))
{
const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data);
_pc += processed;
return processed;
}
#ifndef Z7_EXTRACT_ONLY
Z7_COM7F_IMF(CEncoder::Init())
{
_pc = _pc_Init;
return S_OK;
}
Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
{
const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data);
_pc += processed;
return processed;
}
Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
{
UInt32 pc = 0;
for (UInt32 i = 0; i < numProps; i++)
{
const PROPID propID = propIDs[i];
if (propID == NCoderPropID::kDefaultProp ||
propID == NCoderPropID::kBranchOffset)
{
const PROPVARIANT &prop = props[i];
if (prop.vt != VT_UI4)
return E_INVALIDARG;
pc = prop.ulVal;
if (pc & _alignment)
return E_INVALIDARG;
}
}
_pc_Init = pc;
return S_OK;
}
Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
{
if (_pc_Init == 0)
return S_OK;
UInt32 buf32[1];
SetUi32(buf32, _pc_Init)
return WriteStream(outStream, buf32, 4);
}
#endif
Z7_COM7F_IMF(CDecoder::Init())
{
_pc = _pc_Init;
return S_OK;
}
Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
{
const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data);
_pc += processed;
return processed;
}
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size))
{
UInt32 val = 0;
if (size != 0)
{
if (size != 4)
return E_NOTIMPL;
val = GetUi32(props);
if (val & _alignment)
return E_NOTIMPL;
}
_pc_Init = val;
return S_OK;
}
}}
@@ -0,0 +1,59 @@
// BranchMisc.h
#ifndef ZIP7_INC_COMPRESS_BRANCH_MISC_H
#define ZIP7_INC_COMPRESS_BRANCH_MISC_H
#include "../../../C/Bra.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
namespace NBranch {
Z7_CLASS_IMP_COM_1(
CCoder
, ICompressFilter
)
UInt32 _pc;
z7_Func_BranchConv BraFunc;
public:
CCoder(z7_Func_BranchConv bra): _pc(0), BraFunc(bra) {}
};
#ifndef Z7_EXTRACT_ONLY
Z7_CLASS_IMP_COM_3(
CEncoder
, ICompressFilter
, ICompressSetCoderProperties
, ICompressWriteCoderProperties
)
UInt32 _pc;
UInt32 _pc_Init;
UInt32 _alignment;
z7_Func_BranchConv BraFunc;
public:
CEncoder(z7_Func_BranchConv bra, UInt32 alignment):
_pc(0), _pc_Init(0), _alignment(alignment), BraFunc(bra) {}
};
#endif
Z7_CLASS_IMP_COM_2(
CDecoder
, ICompressFilter
, ICompressSetDecoderProperties2
)
UInt32 _pc;
UInt32 _pc_Init;
UInt32 _alignment;
z7_Func_BranchConv BraFunc;
public:
CDecoder(z7_Func_BranchConv bra, UInt32 alignment):
_pc(0), _pc_Init(0), _alignment(alignment), BraFunc(bra) {}
};
}}
#endif
@@ -0,0 +1,58 @@
// BranchRegister.cpp
#include "StdAfx.h"
#include "../Common/RegisterCodec.h"
#include "BranchMisc.h"
namespace NCompress {
namespace NBranch {
#ifdef Z7_EXTRACT_ONLY
#define GET_CREATE_FUNC(x) NULL
#define CREATE_BRA_E(n)
#else
#define GET_CREATE_FUNC(x) x
#define CREATE_BRA_E(n) \
REGISTER_FILTER_CREATE(CreateBra_Encoder_ ## n, CCoder(Z7_BRANCH_CONV_ENC_2(n)))
#endif
#define CREATE_BRA(n) \
REGISTER_FILTER_CREATE(CreateBra_Decoder_ ## n, CCoder(Z7_BRANCH_CONV_DEC_2(n))) \
CREATE_BRA_E(n)
CREATE_BRA(BranchConv_PPC)
CREATE_BRA(BranchConv_IA64)
CREATE_BRA(BranchConv_ARM)
CREATE_BRA(BranchConv_ARMT)
CREATE_BRA(BranchConv_SPARC)
#define METHOD_ITEM(n, id, name) \
REGISTER_FILTER_ITEM( \
CreateBra_Decoder_ ## n, GET_CREATE_FUNC( \
CreateBra_Encoder_ ## n), \
0x3030000 + id, name)
REGISTER_CODECS_VAR
{
METHOD_ITEM(BranchConv_PPC, 0x205, "PPC"),
METHOD_ITEM(BranchConv_IA64, 0x401, "IA64"),
METHOD_ITEM(BranchConv_ARM, 0x501, "ARM"),
METHOD_ITEM(BranchConv_ARMT, 0x701, "ARMT"),
METHOD_ITEM(BranchConv_SPARC, 0x805, "SPARC")
};
REGISTER_CODECS(Branch)
#define REGISTER_FILTER_E_BRANCH(id, n, name, alignment) \
REGISTER_FILTER_E(n, \
CDecoder(Z7_BRANCH_CONV_DEC(n), alignment), \
CEncoder(Z7_BRANCH_CONV_ENC(n), alignment), \
id, name)
REGISTER_FILTER_E_BRANCH(0xa, ARM64, "ARM64", 3)
REGISTER_FILTER_E_BRANCH(0xb, RISCV, "RISCV", 1)
}}
@@ -0,0 +1,91 @@
// ByteSwap.cpp
#include "StdAfx.h"
#include "../../../C/SwapBytes.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "../Common/RegisterCodec.h"
namespace NCompress {
namespace NByteSwap {
Z7_CLASS_IMP_COM_1(CByteSwap2, ICompressFilter) };
Z7_CLASS_IMP_COM_1(CByteSwap4, ICompressFilter) };
Z7_COM7F_IMF(CByteSwap2::Init()) { return S_OK; }
Z7_COM7F_IMF2(UInt32, CByteSwap2::Filter(Byte *data, UInt32 size))
{
const UInt32 kMask = 2 - 1;
size &= ~kMask;
/*
if ((unsigned)(ptrdiff_t)data & kMask)
{
if (size == 0)
return 0;
const Byte *end = data + (size_t)size;
do
{
const Byte b0 = data[0];
data[0] = data[1];
data[1] = b0;
data += kStep;
}
while (data != end);
}
else
*/
z7_SwapBytes2((UInt16 *)(void *)data, size >> 1);
return size;
}
Z7_COM7F_IMF(CByteSwap4::Init()) { return S_OK; }
Z7_COM7F_IMF2(UInt32, CByteSwap4::Filter(Byte *data, UInt32 size))
{
const UInt32 kMask = 4 - 1;
size &= ~kMask;
/*
if ((unsigned)(ptrdiff_t)data & kMask)
{
if (size == 0)
return 0;
const Byte *end = data + (size_t)size;
do
{
const Byte b0 = data[0];
const Byte b1 = data[1];
data[0] = data[3];
data[1] = data[2];
data[2] = b1;
data[3] = b0;
data += kStep;
}
while (data != end);
}
else
*/
z7_SwapBytes4((UInt32 *)(void *)data, size >> 2);
return size;
}
static struct C_SwapBytesPrepare { C_SwapBytesPrepare() { z7_SwapBytesPrepare(); } } g_SwapBytesPrepare;
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,7 @@
EXPORTS
CreateObject PRIVATE
GetNumberOfMethods PRIVATE
GetMethodProperty PRIVATE
CreateDecoder PRIVATE
CreateEncoder PRIVATE
GetModuleProp PRIVATE
@@ -0,0 +1,378 @@
// CodecExports.cpp
#include "StdAfx.h"
#include "../../../C/CpuArch.h"
#include "../../../C/7zVersion.h"
#include "../../Common/ComTry.h"
#include "../../Common/MyCom.h"
#include "../../Windows/Defs.h"
#include "../../Windows/PropVariant.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()
{
const 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;
const 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 = (int)i;
return S_OK;
}
return S_OK;
}
/*
#ifdef __GNUC__
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wduplicated-branches"
#endif
#endif
*/
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;
unk = (IUnknown *)c;
/*
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);
STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject)
{
return CreateCoder2(false, index, iid, outObject);
}
STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **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);
STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
{
*outObject = NULL;
bool isFilter = false;
bool isCoder2 = false;
const 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;
const HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);
if (res != S_OK)
return res;
if (codecIndex < 0)
return CLASS_E_CLASSNOTAVAILABLE;
return CreateCoderMain((unsigned)codecIndex, encode, outObject);
}
STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
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:
{
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);
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;
const UInt64 id = GetUi64(clsid->Data4);
for (unsigned i = 0; i < g_NumCodecs; i++)
if (id == g_Hashers[i]->Id)
return (int)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);
STDAPI CreateHasher(const GUID *clsid, IHasher **outObject)
{
COM_TRY_BEGIN
*outObject = NULL;
const int index = FindHasherClassId(clsid);
if (index < 0)
return CLASS_E_CLASSNOTAVAILABLE;
return CreateHasher2((UInt32)(unsigned)index, outObject);
COM_TRY_END
}
STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
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;
}
Z7_CLASS_IMP_COM_1(CHashers, IHashers) };
STDAPI GetHashers(IHashers **hashers);
STDAPI GetHashers(IHashers **hashers)
{
COM_TRY_BEGIN
*hashers = new CHashers;
if (*hashers)
(*hashers)->AddRef();
return S_OK;
COM_TRY_END
}
Z7_COM7F_IMF2(UInt32, CHashers::GetNumHashers())
{
return g_NumHashers;
}
Z7_COM7F_IMF(CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value))
{
return ::GetHasherProp(index, propID, value);
}
Z7_COM7F_IMF(CHashers::CreateHasher(UInt32 index, IHasher **hasher))
{
return ::CreateHasher2(index, hasher);
}
STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value);
STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value)
{
::VariantClear((VARIANTARG *)value);
switch (propID)
{
case NModulePropID::kInterfaceType:
{
NWindows::NCOM::PropVarEm_Set_UInt32(value, NModuleInterfaceType::k_IUnknown_VirtDestructor_ThisModule);
break;
}
case NModulePropID::kVersion:
{
NWindows::NCOM::PropVarEm_Set_UInt32(value, (MY_VER_MAJOR << 16) | MY_VER_MINOR);
break;
}
}
return S_OK;
}
@@ -0,0 +1,153 @@
// 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);
}
Z7_COM7F_IMF(CCopyCoder::SetFinishMode(UInt32 /* finishMode */))
{
return S_OK;
}
Z7_COM7F_IMF(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)
{
const UInt64 rem = *outSize - TotalSize;
if (size > rem)
{
size = (UInt32)rem;
if (size == 0)
{
/* if we enable the following check,
we will make one call of Read(_buf, 0) for empty stream */
// if (TotalSize != 0)
return S_OK;
}
}
}
HRESULT readRes;
{
UInt32 pos = 0;
do
{
const UInt32 curSize = size - pos;
UInt32 processed = 0;
readRes = inStream->Read(_buf + pos, curSize, &processed);
if (processed > curSize)
return E_FAIL; // internal code failure
pos += processed;
if (readRes != S_OK || processed == 0)
break;
}
while (pos < kBufSize);
size = pos;
}
if (size == 0)
return readRes;
if (outStream)
{
UInt32 pos = 0;
do
{
const UInt32 curSize = size - pos;
UInt32 processed = 0;
const HRESULT res = outStream->Write(_buf + pos, curSize, &processed);
if (processed > curSize)
return E_FAIL; // internal code failure
pos += processed;
TotalSize += processed;
RINOK(res)
if (processed == 0)
return E_FAIL;
}
while (pos < size);
}
else
TotalSize += size;
RINOK(readRes)
if (size != kBufSize)
return S_OK;
if (progress && (TotalSize & (((UInt32)1 << 22) - 1)) == 0)
{
RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize))
}
}
}
Z7_COM7F_IMF(CCopyCoder::SetInStream(ISequentialInStream *inStream))
{
_inStream = inStream;
TotalSize = 0;
return S_OK;
}
Z7_COM7F_IMF(CCopyCoder::ReleaseInStream())
{
_inStream.Release();
return S_OK;
}
Z7_COM7F_IMF(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;
}
Z7_COM7F_IMF(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,34 @@
// Compress/CopyCoder.h
#ifndef ZIP7_INC_COMPRESS_COPY_CODER_H
#define ZIP7_INC_COMPRESS_COPY_CODER_H
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
Z7_CLASS_IMP_COM_5(
CCopyCoder
, ICompressCoder
, ICompressSetInStream
, ISequentialInStream
, ICompressSetFinishMode
, ICompressGetInStreamProcessedSize
)
Byte *_buf;
CMyComPtr<ISequentialInStream> _inStream;
public:
UInt64 TotalSize;
CCopyCoder(): _buf(NULL), TotalSize(0) {}
~CCopyCoder();
};
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,25 @@
// Deflate64Register.cpp
#include "StdAfx.h"
#include "../Common/RegisterCodec.h"
#include "DeflateDecoder.h"
#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY)
#include "DeflateEncoder.h"
#endif
namespace NCompress {
namespace NDeflate {
REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder64())
#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_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 ZIP7_INC_DEFLATE_CONST_H
#define ZIP7_INC_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,566 @@
// DeflateDecoder.cpp
#include "StdAfx.h"
#include "DeflateDecoder.h"
namespace NCompress {
namespace NDeflate {
namespace NDecoder {
CCoder::CCoder(bool deflate64Mode):
_deflateNSIS(false),
_deflate64Mode(deflate64Mode),
_keepHistory(false),
_needFinishInput(false),
_needInitInStream(true),
_outSizeDefined(false),
_outStartPos(0)
{}
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
{
unsigned 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;
const 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
{
const unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;
_numDistLevels = (unsigned)ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;
const unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;
if (!_deflate64Mode)
if (_numDistLevels > kDistTableSize32)
return false;
const unsigned kLevelTableSize_aligned4 = kLevelTableSize + 1;
Byte levelLevels[kLevelTableSize_aligned4];
memset (levelLevels, 0, sizeof(levelLevels));
unsigned i = 0;
do
levelLevels[kCodeLengthAlphabetOrder[i++]] = (Byte)ReadBits(kLevelFieldSize);
while (i != numLevelCodes);
if (m_InBitStream.ExtraBitsWereRead())
return false;
RIF(m_LevelDecoder.Build(levelLevels, false)) // full
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;
}
// _remainLen >= 0
while (_remainLen && curSize)
{
_remainLen--;
const Byte b = m_OutWindowStream.GetByte(_rep0);
m_OutWindowStream.PutByte(b);
curSize--;
}
UInt64 inputStart = 0;
if (inputProgressLimit != 0)
inputStart = m_InBitStream.GetProcessedSize();
while (curSize || 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 */
UInt32 num = m_StoredBlockSize;
if (num > curSize)
num = curSize;
m_StoredBlockSize -= num;
curSize -= num;
for (; num && m_InBitStream.ThereAreDataInBitsBuffer(); num--)
m_OutWindowStream.PutByte(ReadAlignedByte());
if (num)
{
#if 1
// fast code
do
{
size_t a;
Byte *buf = m_OutWindowStream.GetOutBuffer(a);
// a != 0
if (a > num)
a = num;
// a != 0
a = m_InBitStream.ReadDirectBytesPart(buf, a);
if (a == 0)
return S_FALSE;
m_OutWindowStream.SkipWrittenBytes(a);
num -= (UInt32)a;
}
while (num);
#else
// slow code:
do
m_OutWindowStream.PutByte(m_InBitStream.ReadDirectByte());
while (--num);
#endif
}
_needReadTable = (m_StoredBlockSize == 0);
continue;
}
while (curSize)
{
if (m_InBitStream.ExtraBitsWereRead_Fast())
return S_FALSE;
unsigned sym;
#if 0
sym = m_MainDecoder.Decode(&m_InBitStream);
#else
Z7_HUFF_DECODE_CHECK(sym, &m_MainDecoder, kNumHuffmanBits, kNumTableBits_Main, &m_InBitStream, { return S_FALSE; })
#endif
if (sym < 0x100)
{
m_OutWindowStream.PutByte((Byte)sym);
curSize--;
continue;
}
if (sym == kSymbolEndOfBlock)
{
_needReadTable = true;
break;
}
#if 0
if (sym >= kMainTableSize)
return S_FALSE;
#endif
{
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);
}
#if 0
sym = m_DistDecoder.Decode(&m_InBitStream);
if (sym >= _numDistLevels)
return S_FALSE;
#else
Z7_HUFF_DECODE_CHECK(sym, &m_DistDecoder, kNumHuffmanBits, kNumTableBits_Dist, &m_InBitStream, { return S_FALSE; })
#endif
#if 1
sym = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
#else
if (sym >= 4)
{
// sym &= 31;
const unsigned numDirectBits = (sym - 2) >> 1;
sym = (2u | (sym & 1)) << numDirectBits;
sym += m_InBitStream.ReadBits(numDirectBits);
}
#endif
UInt32 locLen = len;
if (locLen > curSize)
locLen = (UInt32)curSize;
if (!m_OutWindowStream.CopyBlock(sym, locLen))
return S_FALSE;
curSize -= locLen;
len -= locLen;
if (len != 0)
{
_remainLen = (Int32)len;
_rep0 = sym;
break;
}
}
}
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 Z7_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 (_needFinishInput)
finishInputStream = true;
else if (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))
}
}
flusher.NeedFlush = false;
res = Flush();
if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError())
return S_FALSE;
DEFLATE_TRY_END(res)
return res;
}
Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
{
SetInStream(inStream);
SetOutStreamSize(outSize);
const HRESULT res = CodeReal(outStream, progress);
ReleaseInStream();
/*
if (res == S_OK)
if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize())
res = S_FALSE;
*/
return res;
}
Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode))
{
Set_NeedFinishInput(finishMode != 0);
return S_OK;
}
Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value))
{
*value = m_InBitStream.GetStreamSize();
return S_OK;
}
Z7_COM7F_IMF(CCoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize))
{
AlignToByte();
UInt32 i = 0;
{
for (i = 0; i < size; i++)
{
if (!m_InBitStream.ReadAlignedByte_FromBuf(((Byte *)data)[i]))
break;
}
}
if (processedSize)
*processedSize = i;
return S_OK;
}
Z7_COM7F_IMF(CCoder::SetInStream(ISequentialInStream *inStream))
{
m_InStreamRef = inStream;
m_InBitStream.SetStream(inStream);
return S_OK;
}
Z7_COM7F_IMF(CCoder::ReleaseInStream())
{
m_InStreamRef.Release();
m_InBitStream.ClearStreamPtr();
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;
}
Z7_COM7F_IMF(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 Z7_NO_READ_FROM_CODER
Z7_COM7F_IMF(CCoder::Read(void *data, UInt32 size, UInt32 *processedSize))
{
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 (_needFinishInput)
finishInputStream = true;
}
}
if (!finishInputStream && size == 0)
return S_OK;
HRESULT res;
DEFLATE_TRY_BEGIN
m_OutWindowStream.SetMemStream((Byte *)data);
res = CodeSpec(size, finishInputStream);
DEFLATE_TRY_END(res)
{
const 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,154 @@
// DeflateDecoder.h
#ifndef ZIP7_INC_DEFLATE_DECODER_H
#define ZIP7_INC_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;
const unsigned kNumTableBits_Main = 10;
const unsigned kNumTableBits_Dist = 6;
class CCoder:
public ICompressCoder,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public ICompressReadUnusedFromInBuf,
public ICompressSetInStream,
public ICompressSetOutStreamSize,
#ifndef Z7_NO_READ_FROM_CODER
public ISequentialInStream,
#endif
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(ICompressCoder)
Z7_COM_QI_ENTRY(ICompressSetFinishMode)
Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf)
Z7_COM_QI_ENTRY(ICompressSetInStream)
Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
#ifndef Z7_NO_READ_FROM_CODER
Z7_COM_QI_ENTRY(ISequentialInStream)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(ICompressCoder)
Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
public:
Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf)
Z7_IFACE_COM7_IMP(ICompressSetInStream)
private:
Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
#ifndef Z7_NO_READ_FROM_CODER
Z7_IFACE_COM7_IMP(ISequentialInStream)
#endif
CLzOutWindow m_OutWindowStream;
NBitl::CDecoder<CInBuffer> m_InBitStream;
NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedMainTableSize, kNumTableBits_Main> m_MainDecoder;
NCompress::NHuffman::CDecoder256<kNumHuffmanBits, kFixedDistTableSize, kNumTableBits_Dist> m_DistDecoder;
NCompress::NHuffman::CDecoder7b<kLevelTableSize> m_LevelDecoder;
UInt32 m_StoredBlockSize;
unsigned _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;
CMyComPtr<ISequentialInStream> m_InStreamRef;
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:
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);
public:
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
{
const UInt32 v = m_InBitStream.ReadAlignedByte();
return v | ((UInt32)m_InBitStream.ReadAlignedByte() << 8);
}
bool InputEofError() const { return m_InBitStream.ExtraBitsWereRead(); }
// size of used real data from input stream
UInt64 GetStreamSize() const { return m_InBitStream.GetStreamSize(); }
// size of virtual input stream processed
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,203 @@
// DeflateEncoder.h
#ifndef ZIP7_INC_DEFLATE_ENCODER_H
#define ZIP7_INC_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 Z7_final:
public ICompressCoder,
public ICompressSetCoderProperties,
public CMyUnknownImp,
public CCoder
{
Z7_IFACES_IMP_UNK_2(ICompressCoder, ICompressSetCoderProperties)
public:
CCOMCoder(): CCoder(false) {}
};
class CCOMCoder64 Z7_final:
public ICompressCoder,
public ICompressSetCoderProperties,
public CMyUnknownImp,
public CCoder
{
Z7_IFACES_IMP_UNK_2(ICompressCoder, ICompressSetCoderProperties)
public:
CCOMCoder64(): CCoder(true) {}
};
}}}
#endif
@@ -0,0 +1,25 @@
// DeflateRegister.cpp
#include "StdAfx.h"
#include "../Common/RegisterCodec.h"
#include "DeflateDecoder.h"
#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY)
#include "DeflateEncoder.h"
#endif
namespace NCompress {
namespace NDeflate {
REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder)
#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_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,126 @@
// 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 Z7_EXTRACT_ONLY
class CEncoder Z7_final:
public ICompressFilter,
public ICompressSetCoderProperties,
public ICompressWriteCoderProperties,
public CMyUnknownImp,
CDelta
{
Z7_IFACES_IMP_UNK_3(
ICompressFilter,
ICompressSetCoderProperties,
ICompressWriteCoderProperties)
};
Z7_COM7F_IMF(CEncoder::Init())
{
DeltaInit();
return S_OK;
}
Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
{
Delta_Encode(_state, _delta, data, size);
return size;
}
Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
{
unsigned delta = _delta;
for (UInt32 i = 0; i < numProps; i++)
{
const PROPVARIANT &prop = props[i];
const PROPID propID = propIDs[i];
if (propID >= NCoderPropID::kReduceSize)
continue;
if (prop.vt != VT_UI4)
return E_INVALIDARG;
switch (propID)
{
case NCoderPropID::kDefaultProp:
if (prop.ulVal < 1 || prop.ulVal > 256)
return E_INVALIDARG;
delta = prop.ulVal;
break;
case NCoderPropID::kNumThreads: break;
case NCoderPropID::kLevel: break;
default: return E_INVALIDARG;
}
}
_delta = delta;
return S_OK;
}
Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
{
const Byte prop = (Byte)(_delta - 1);
return outStream->Write(&prop, 1, NULL);
}
#endif
class CDecoder Z7_final:
public ICompressFilter,
public ICompressSetDecoderProperties2,
public CMyUnknownImp,
CDelta
{
Z7_IFACES_IMP_UNK_2(
ICompressFilter,
ICompressSetDecoderProperties2)
};
Z7_COM7F_IMF(CDecoder::Init())
{
DeltaInit();
return S_OK;
}
Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
{
Delta_Decode(_state, _delta, data, size);
return size;
}
Z7_COM7F_IMF(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,38 @@
// 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*/);
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);
STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
{
return CreateCoder(clsid, iid, outObject);
}
@@ -0,0 +1,59 @@
// 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*/);
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);
STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
{
return CreateCoder(clsid, iid, outObject);
}
@@ -0,0 +1,527 @@
// Compress/HuffmanDecoder.h
#ifndef ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H
#define ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H
#include "../../../C/CpuArch.h"
#include "../../Common/MyTypes.h"
namespace NCompress {
namespace NHuffman {
// const unsigned kNumTableBits_Default = 9;
#if 0 || 0 && defined(MY_CPU_64BIT)
// for debug or optimization:
// 64-BIT limit array can be faster for some compilers.
// for debug or optimization:
#define Z7_HUFF_USE_64BIT_LIMIT
#else
// sizet value variable allows to eliminate some move operation in some compilers.
// for debug or optimization:
// #define Z7_HUFF_USE_SIZET_VALUE
#endif
// v0 must normalized to (32 bits) : (v0 < ((UInt64)1 << 32))
#ifdef Z7_HUFF_USE_64BIT_LIMIT
typedef UInt64 CLimitInt;
typedef UInt64 CValueInt;
// all _limits[*] are normalized and limited by ((UInt64)1 << 32).
// we don't use (v1) in this branch
#define Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) 32
#define Z7_HUFF_TABLE_COMPARE(huf, kNumTableBits, v0, v1) \
((NCompress::NHuffman::CLimitInt)v0 >= (huf)->_limits[0])
#define Z7_HUFF_GET_VAL_FOR_LIMITS(v0, v1, kNumBitsMax, kNumTableBits) (v0)
#define Z7_HUFF_GET_VAL_FOR_TABLE( v0, v1, kNumBitsMax, kNumTableBits) ((v0) >> (32 - kNumTableBits))
#define Z7_HUFF_PRECALC_V1(kNumTableBits, v0, v1)
#else
typedef UInt32 CLimitInt;
typedef
#ifdef Z7_HUFF_USE_SIZET_VALUE
size_t
#else
UInt32
#endif
CValueInt;
// v1 must be precalculated from v0 in this branch
// _limits[0] and (v1) are normalized and limited by (1 << kNumTableBits).
// _limits[non_0] are normalized and limited by (1 << kNumBitsMax).
#define Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) (kNumBitsMax)
#define Z7_HUFF_TABLE_COMPARE(huf, kNumTableBits, v0, v1) \
((NCompress::NHuffman::CLimitInt)v1 >= (huf)->_limits[0])
#define Z7_HUFF_GET_VAL_FOR_LIMITS(v0, v1, kNumBitsMax, kNumTableBits) ((v0) >> (32 - kNumBitsMax))
#define Z7_HUFF_GET_VAL_FOR_TABLE( v0, v1, kNumBitsMax, kNumTableBits) (v1)
#define Z7_HUFF_PRECALC_V1(kNumTableBits, v0, v1) const UInt32 v1 = ((v0) >> (32 - kNumTableBits));
#endif
enum enum_BuildMode
{
k_BuildMode_Partial = 0,
k_BuildMode_Full = 1,
k_BuildMode_Full_or_Empty = 2
};
template <class symType, class symType2, class symType4, unsigned kNumBitsMax, unsigned m_NumSymbols, unsigned kNumTableBits /* = kNumTableBits_Default */>
struct CDecoderBase
{
CLimitInt _limits[kNumBitsMax + 2 - kNumTableBits];
UInt32 _poses[kNumBitsMax - kNumTableBits]; // unsigned
union
{
// if defined(MY_CPU_64BIT), we need 64-bit alignment for _symbols.
// if !defined(MY_CPU_64BIT), we need 32-bit alignment for _symbols
// but we provide alignment for _lens.
// _symbols also will be aligned, if _lens are aligned
#if defined(MY_CPU_64BIT)
UInt64
#else
UInt32
#endif
_pad_align[m_NumSymbols < (1u << sizeof(symType) * 8) ? 1 : -1];
/* if symType is Byte, we use 16-bytes padding to avoid cache
bank conflict between _lens and _symbols: */
Byte _lens[(1 << kNumTableBits) + (sizeof(symType) == 1 ? 16 : 0)];
} _u;
symType _symbols[(1 << kNumTableBits) + m_NumSymbols - (kNumTableBits + 1)];
/*
Z7_FORCE_INLINE
bool IsFull() const
{
return _limits[kNumBitsMax - kNumTableBits] ==
(CLimitInt)1u << Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax);
}
Z7_FORCE_INLINE
bool IsEmpty() const
{
return _limits[kNumBitsMax - kNumTableBits] == 0;
}
Z7_FORCE_INLINE
bool Is_Full_or_Empty() const
{
return 0 == (_limits[kNumBitsMax - kNumTableBits] &
~((CLimitInt)1 << Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax)));
}
*/
Z7_FORCE_INLINE
bool Build(const Byte *lens, enum_BuildMode buidMode = k_BuildMode_Partial) throw()
{
unsigned counts[kNumBitsMax + 1];
size_t i;
for (i = 0; i <= kNumBitsMax; i++)
counts[i] = 0;
for (i = 0; i < m_NumSymbols; i++)
counts[lens[i]]++;
UInt32 sum = 0;
for (i = 1; i <= kNumTableBits; i++)
{
sum <<= 1;
sum += counts[i];
}
CLimitInt startPos = (CLimitInt)sum;
_limits[0] =
#ifdef Z7_HUFF_USE_64BIT_LIMIT
startPos << (Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - kNumTableBits);
#else
startPos;
#endif
for (i = kNumTableBits + 1; i <= kNumBitsMax; i++)
{
startPos <<= 1;
_poses[i - (kNumTableBits + 1)] = (UInt32)(startPos - sum);
const unsigned cnt = counts[i];
counts[i] = sum;
sum += cnt;
startPos += cnt;
_limits[i - kNumTableBits] = startPos << (Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - i);
}
_limits[kNumBitsMax + 1 - kNumTableBits] =
(CLimitInt)1 << Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax);
if (buidMode == k_BuildMode_Partial)
{
if (startPos > (1u << kNumBitsMax)) return false;
}
else
{
if (buidMode != k_BuildMode_Full && startPos == 0) return true;
if (startPos != (1u << kNumBitsMax)) return false;
}
size_t sum2 = 0;
for (i = 1; i <= kNumTableBits; i++)
{
const unsigned cnt = counts[i] << (kNumTableBits - i);
counts[i] = (unsigned)sum2 >> (kNumTableBits - i);
memset(_u._lens + sum2, (int)i, cnt);
sum2 += cnt;
}
#ifdef MY_CPU_64BIT
symType4
// UInt64 // for symType = UInt16
// UInt32 // for symType = Byte
#else
UInt32
#endif
v = 0;
for (i = 0; i < m_NumSymbols; i++,
v +=
1
+ ( (UInt32)1 << (sizeof(symType) * 8 * 1))
// 0x00010001 // for symType = UInt16
// 0x00000101 // for symType = Byte
#ifdef MY_CPU_64BIT
+ ((symType4)1 << (sizeof(symType) * 8 * 2))
+ ((symType4)1 << (sizeof(symType) * 8 * 3))
// 0x0001000100010001 // for symType = UInt16
// 0x0000000001010101 // for symType = Byte
#endif
)
{
const unsigned len = lens[i];
if (len == 0)
continue;
const size_t offset = counts[len];
counts[len] = (unsigned)offset + 1;
if (len >= kNumTableBits)
_symbols[offset] = (symType)v;
else
{
Byte *s2 = (Byte *)(void *)_symbols + (offset <<
(kNumTableBits + sizeof(symType) / 2 - len));
Byte *lim = s2 + ((size_t)1 <<
(kNumTableBits + sizeof(symType) / 2 - len));
if (len >= kNumTableBits - 2)
{
*(symType2 *)(void *)(s2 ) = (symType2)v;
*(symType2 *)(void *)(lim - sizeof(symType) * 2) = (symType2)v;
}
else
{
#ifdef MY_CPU_64BIT
symType4 *s = (symType4 *)(void *)s2;
do
{
s[0] = v; s[1] = v; s += 2;
}
while (s != (const symType4 *)(const void *)lim);
#else
symType2 *s = (symType2 *)(void *)s2;
do
{
s[0] = (symType2)v; s[1] = (symType2)v; s += 2;
s[0] = (symType2)v; s[1] = (symType2)v; s += 2;
}
while (s != (const symType2 *)(const void *)lim);
#endif
}
}
}
return true;
}
#define Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES(_numBits_, kNumBitsMax, error_op) if (_numBits_ > kNumBitsMax) { error_op }
#define Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO( _numBits_, kNumBitsMax, error_op)
#define Z7_HUFF_DECODE_BASE_TREE_BRANCH(sym, huf, kNumBitsMax, kNumTableBits, \
v0, v1, \
get_val_for_limits, \
check_op, error_op, _numBits_) \
{ \
const NHuffman::CValueInt _val = get_val_for_limits(v0, v1, kNumBitsMax, kNumTableBits); \
_numBits_ = kNumTableBits + 1; \
if ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[1]) \
do { _numBits_++; } \
while ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[_numBits_ - kNumTableBits]); \
check_op(_numBits_, kNumBitsMax, error_op) \
sym = (huf)->_symbols[(/* (UInt32) */ (_val >> ((Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - (unsigned)_numBits_)))) \
- (huf)->_poses[_numBits_ - (kNumTableBits + 1)]]; \
}
/*
Z7_HUFF_DECODE_BASE_TREE_BRANCH(sym, huf, kNumBitsMax, kNumTableBits, \
v0, v1, \
get_val_for_limits, \
check_op, error_op, _numBits_) \
*/
#define Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \
v0, v1, \
get_val_for_table, get_val_for_limits, \
check_op, error_op, move_pos_op, after_op, bs) \
{ \
if (Z7_HUFF_TABLE_COMPARE(huf, kNumTableBits, v0, v1)) \
{ \
const NHuffman::CValueInt _val = get_val_for_limits(v0, v1, kNumBitsMax, kNumTableBits); \
size_t _numBits_ = kNumTableBits + 1; \
if ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[1]) \
do { _numBits_++; } \
while ((NCompress::NHuffman::CLimitInt)_val >= (huf)->_limits[_numBits_ - kNumTableBits]); \
check_op(_numBits_, kNumBitsMax, error_op) \
sym = (huf)->_symbols[(/* (UInt32) */ (_val >> ((Z7_HUFF_NUM_LIMIT_BITS(kNumBitsMax) - (unsigned)_numBits_)))) \
- (huf)->_poses[_numBits_ - (kNumTableBits + 1)]]; \
move_pos_op(bs, _numBits_); \
} \
else \
{ \
const size_t _val = get_val_for_table(v0, v1, kNumBitsMax, kNumTableBits); \
const size_t _numBits_ = (huf)->_u._lens[_val]; \
sym = (huf)->_symbols[_val]; \
move_pos_op(bs, _numBits_); \
} \
after_op \
}
#define Z7_HUFF_DECODE_10(sym, huf, kNumBitsMax, kNumTableBits, \
v0, v1, \
check_op, error_op, move_pos_op, after_op, bs) \
Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \
v0, v1, \
Z7_HUFF_GET_VAL_FOR_TABLE, \
Z7_HUFF_GET_VAL_FOR_LIMITS, \
check_op, error_op, move_pos_op, after_op, bs) \
#define Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, huf, kNumBitsMax, kNumTableBits, \
v0, \
check_op, error_op, move_pos_op, after_op, bs) \
{ \
Z7_HUFF_PRECALC_V1(kNumTableBits, v0, _v1_temp) \
Z7_HUFF_DECODE_10(sym, huf, kNumBitsMax, kNumTableBits, \
v0, _v1_temp, \
check_op, error_op, move_pos_op, after_op, bs) \
}
#if 0 || defined(Z7_HUFF_USE_64BIT_LIMIT)
// this branch uses bitStream->GetValue_InHigh32bits().
#define Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, \
check_op, error_op, move_pos_op) \
{ \
const UInt32 v0 = (bitStream)->GetValue_InHigh32bits(); \
Z7_HUFF_PRECALC_V1(kNumTableBits, v0, v1); \
Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \
v0, v1, \
Z7_HUFF_GET_VAL_FOR_TABLE, \
Z7_HUFF_GET_VAL_FOR_LIMITS, \
check_op, error_op, move_pos_op, {}, bitStream) \
}
#else
/*
this branch uses bitStream->GetValue().
So we use SIMPLE versions for v0, v1 calculation:
v0 is normalized for kNumBitsMax
v1 is normalized for kNumTableBits
*/
#define Z7_HUFF_GET_VAL_FOR_LIMITS_SIMPLE(v0, v1, kNumBitsMax, kNumTableBits) v0
#define Z7_HUFF_GET_VAL_FOR_TABLE_SIMPLE( v0, v1, kNumBitsMax, kNumTableBits) v1
#define Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op, move_pos_op) \
{ \
const UInt32 v0 = (bitStream)->GetValue(kNumBitsMax); \
const UInt32 v1 = v0 >> (kNumBitsMax - kNumTableBits); \
Z7_HUFF_DECODE_BASE(sym, huf, kNumBitsMax, kNumTableBits, \
v0, v1, \
Z7_HUFF_GET_VAL_FOR_TABLE_SIMPLE, \
Z7_HUFF_GET_VAL_FOR_LIMITS_SIMPLE, \
check_op, error_op, move_pos_op, {}, bitStream) \
}
#endif
#define Z7_HUFF_bitStream_MovePos(bitStream, numBits) (bitStream)->MovePos((unsigned)(numBits))
#define Z7_HUFF_DECODE_1(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op) \
Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op, \
Z7_HUFF_bitStream_MovePos)
// MovePosCheck
#define Z7_HUFF_DECODE_2(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op) \
Z7_HUFF_DECODE_0(sym, huf, kNumBitsMax, kNumTableBits, bitStream, check_op, error_op, \
Z7_HUFF_bitStream_MovePos)
// MovePosCheck
#define Z7_HUFF_DECODE_CHECK(sym, huf, kNumBitsMax, kNumTableBits, bitStream, error_op) \
Z7_HUFF_DECODE_1( sym, huf, kNumBitsMax, kNumTableBits, bitStream, \
Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES, error_op)
template <class TBitDecoder>
Z7_FORCE_INLINE
bool Decode2(TBitDecoder *bitStream, unsigned &sym) const
{
Z7_HUFF_DECODE_CHECK(sym, this, kNumBitsMax, kNumTableBits, bitStream,
{ return false; }
)
return true;
}
template <class TBitDecoder>
Z7_FORCE_INLINE
bool Decode_SymCheck_MovePosCheck(TBitDecoder *bitStream, unsigned &sym) const
{
Z7_HUFF_DECODE_0(sym, this, kNumBitsMax, kNumTableBits, bitStream,
Z7_HUFF_DECODE_ERROR_SYM_CHECK_YES,
{ return false; },
{ return (bitStream)->MovePosCheck; }
)
}
template <class TBitDecoder>
Z7_FORCE_INLINE
unsigned Decode(TBitDecoder *bitStream) const
{
unsigned sym;
Z7_HUFF_DECODE_CHECK(sym, this, kNumBitsMax, kNumTableBits, bitStream,
{ return (unsigned)(int)(Int32)0xffffffff; }
)
return sym;
}
template <class TBitDecoder>
Z7_FORCE_INLINE
unsigned DecodeFull(TBitDecoder *bitStream) const
{
/*
const UInt32 val = bitStream->GetValue(kNumBitsMax);
if (val < _limits[kNumTableBits])
{
const unsigned pair = _u._lens[(size_t)(val >> (kNumBitsMax - kNumTableBits))];
bitStream->MovePos(pair & kPairLenMask);
return pair >> kNumPairLenBits;
}
unsigned numBits;
for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
bitStream->MovePos(numBits);
return _symbols[_poses[numBits] + (unsigned)
((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits))];
*/
unsigned sym;
Z7_HUFF_DECODE_2(sym, this, kNumBitsMax, kNumTableBits, bitStream,
Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {}
)
return sym;
}
};
template <unsigned kNumBitsMax, unsigned m_NumSymbols, unsigned kNumTableBits /* = kNumTableBits_Default */>
struct CDecoder: public CDecoderBase
<UInt16, UInt32, UInt64, kNumBitsMax, m_NumSymbols, kNumTableBits> {};
template <unsigned kNumBitsMax, unsigned m_NumSymbols, unsigned kNumTableBits /* = 7 */>
struct CDecoder256: public CDecoderBase
<Byte, UInt16, UInt32, kNumBitsMax, m_NumSymbols, kNumTableBits> {};
template <unsigned numSymbols>
class CDecoder7b
{
public:
Byte _lens[1 << 7];
bool Build(const Byte *lens, bool full) throw()
{
const unsigned kNumBitsMax = 7;
unsigned counts[kNumBitsMax + 1];
unsigned _poses[kNumBitsMax + 1];
unsigned _limits[kNumBitsMax + 1];
unsigned i;
for (i = 0; i <= kNumBitsMax; i++)
counts[i] = 0;
for (i = 0; i < numSymbols; i++)
counts[lens[i]]++;
_limits[0] = 0;
const unsigned kMaxValue = 1u << kNumBitsMax;
unsigned startPos = 0;
unsigned sum = 0;
for (i = 1; i <= kNumBitsMax; i++)
{
const unsigned cnt = counts[i];
startPos += cnt << (kNumBitsMax - i);
_limits[i] = startPos;
counts[i] = sum;
_poses[i] = sum;
sum += cnt;
}
counts[0] = sum;
_poses[0] = sum;
if (full)
{
if (startPos != kMaxValue)
return false;
}
else
{
if (startPos > kMaxValue)
return false;
}
for (i = 0; i < numSymbols; i++)
{
const unsigned len = lens[i];
if (len == 0)
continue;
const unsigned offset = counts[len]++;
{
Byte *dest = _lens + _limits[(size_t)len - 1]
+ ((offset - _poses[len]) << (kNumBitsMax - len));
const unsigned num = (unsigned)1 << (kNumBitsMax - len);
const unsigned val = (i << 3) + len;
for (unsigned k = 0; k < num; k++)
dest[k] = (Byte)val;
}
}
if (!full)
{
const unsigned limit = _limits[kNumBitsMax];
const unsigned num = ((unsigned)1 << kNumBitsMax) - limit;
Byte *dest = _lens + limit;
for (unsigned k = 0; k < num; k++)
dest[k] = (Byte)
// (0x1f << 3);
((0x1f << 3) + 0x7);
}
return true;
}
#define Z7_HUFF_DECODER_7B_DECODE(dest, huf, get_val, move_pos, bs) \
{ \
const unsigned pair = huf->_lens[(size_t)get_val(7)]; \
const unsigned numBits = pair & 0x7; \
move_pos(bs, numBits); \
dest = pair >> 3; \
}
template <class TBitDecoder>
unsigned Decode(TBitDecoder *bitStream) const
{
const unsigned pair = _lens[(size_t)bitStream->GetValue(7)];
bitStream->MovePos(pair & 0x7);
return pair >> 3;
}
};
}}
#endif
@@ -0,0 +1,250 @@
// 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;
for (i = 0; i < numSymbols; i++)
counts[lens[i]]++;
const UInt32 kMaxValue = (UInt32)1 << kNumHuffmanBits;
// _limits[0] = kMaxValue;
UInt32 startPos = kMaxValue;
unsigned sum = 0;
for (i = 1; i <= kNumHuffmanBits; i++)
{
const unsigned cnt = counts[i];
const UInt32 range = (UInt32)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 (i = 0; i < numSymbols; i++)
{
const unsigned len = lens[i];
if (len != 0)
_symbols[--counts[len]] = (Byte)i;
}
return true;
}
unsigned CHuffmanDecoder::Decode(CInBit *inStream) const throw()
{
const UInt32 val = inStream->GetValue(kNumHuffmanBits);
size_t numBits;
for (numBits = 1; val < _limits[numBits]; numBits++);
const unsigned sym = _symbols[_poses[numBits]
+ (unsigned)((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():
_flags(0),
_fullStreamMode(false)
{}
bool CCoder::BuildHuff(CHuffmanDecoder &decoder, unsigned numSymbols)
{
Byte levels[kMaxHuffTableSize];
unsigned numRecords = (unsigned)_inBitStream.ReadAlignedByte() + 1;
unsigned index = 0;
do
{
const unsigned b = (unsigned)_inBitStream.ReadAlignedByte();
const unsigned level = (b & 0xF) + 1;
const unsigned rep = ((unsigned)b >> 4) + 1;
if (index + rep > numSymbols)
return false;
for (unsigned j = 0; j < rep; j++)
levels[index++] = (Byte)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 (pos - prevProgress >= (1u << 18) && progress)
{
prevProgress = pos;
const UInt64 packSize = _inBitStream.GetProcessedSize();
RINOK(progress->SetRatioInfo(&packSize, &pos))
}
if (_inBitStream.ReadBits(1) != 0)
{
Byte b;
if (literalsOn)
{
const unsigned sym = _litDecoder.Decode(&_inBitStream);
// if (sym >= kLitTableSize) break;
b = (Byte)sym;
}
else
b = (Byte)_inBitStream.ReadBits(8);
_outWindowStream.PutByte(b);
pos++;
}
else
{
const UInt32 lowDistBits = _inBitStream.ReadBits(numDistDirectBits);
UInt32 dist = (UInt32)_distDecoder.Decode(&_inBitStream);
// if (dist >= kDistTableSize) break;
dist = (dist << numDistDirectBits) + lowDistBits;
unsigned len = _lenDecoder.Decode(&_inBitStream);
// if (len >= kLenTableSize) break;
if (len == kLenTableSize - 1)
len += _inBitStream.ReadBits(kNumLenDirectBits);
len += minMatchLen;
{
const UInt64 limit = unPackSize - pos;
// limit != 0
if (len > limit)
{
moreOut = true;
len = (UInt32)limit;
}
}
do
{
// len != 0
if (dist < pos)
{
_outWindowStream.CopyBlock(dist, len);
pos += len;
break;
}
_outWindowStream.PutByte(0);
pos++;
}
while (--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;
}
Z7_COM7F_IMF(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; }
}
Z7_COM7F_IMF(CCoder::SetDecoderProperties2(const Byte *data, UInt32 size))
{
if (size == 0)
return E_NOTIMPL;
_flags = data[0];
return S_OK;
}
Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode))
{
_fullStreamMode = (finishMode != 0);
return S_OK;
}
Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value))
{
*value = _inBitStream.GetProcessedSize();
return S_OK;
}
}}}
@@ -0,0 +1,61 @@
// ImplodeDecoder.h
#ifndef ZIP7_INC_COMPRESS_IMPLODE_DECODER_H
#define ZIP7_INC_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();
unsigned Decode(CInBit *inStream) const throw();
};
Z7_CLASS_IMP_NOQIB_4(
CCoder
, ICompressCoder
, ICompressSetDecoderProperties2
, ICompressSetFinishMode
, ICompressGetInStreamProcessedSize
)
Byte _flags;
bool _fullStreamMode;
CLzOutWindow _outWindowStream;
CInBit _inBitStream;
CHuffmanDecoder _litDecoder;
CHuffmanDecoder _lenDecoder;
CHuffmanDecoder _distDecoder;
bool BuildHuff(CHuffmanDecoder &table, unsigned numSymbols);
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
public:
CCoder();
};
}}}
#endif
@@ -0,0 +1,3 @@
// ImplodeHuffmanDecoder.cpp
#include "StdAfx.h"
@@ -0,0 +1,6 @@
// ImplodeHuffmanDecoder.h
#ifndef ZIP7_INC_IMPLODE_HUFFMAN_DECODER_H
#define ZIP7_INC_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 Z7_NO_EXCEPTIONS
ErrorCode = S_OK;
#endif
}
@@ -0,0 +1,102 @@
// LzOutWindow.h
#ifndef ZIP7_INC_LZ_OUT_WINDOW_H
#define ZIP7_INC_LZ_OUT_WINDOW_H
#include "../Common/OutBuffer.h"
#ifndef Z7_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,950 @@
// 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;
const 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)
{
PRF(printf("\nLZVN 0x%07x 0x%07x\n", 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;
for (unsigned i = 0; i < 7; i++)
{
Byte b;
if (!m_InStream.ReadByte(b))
return S_FALSE;
if (b != 0)
return S_FALSE;
}
packSize -= 7;
if (packSize)
{
PRF(printf("packSize after unused = %u\n", packSize));
// if (packSize <= 0x100) { Byte buf[0x100]; m_InStream.ReadBytes(buf, packSize); }
/* Lzvn block that is used in HFS can contain junk data
(at least 256 bytes) after payload data. Why?
We ignore that junk data, if it's HFS (LzvnMode) mode. */
if (!LzvnMode)
return S_FALSE;
}
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 Z7_FORCE_INLINE unsigned CountZeroBits(UInt32 val, UInt32 mask)
{
for (unsigned i = 0;;)
{
if (val & mask)
return i;
i++;
mask >>= 1;
}
}
static Z7_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 Z7_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 = (unsigned)(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 \
{ const unsigned nbits = (31 - in.numBits) & (unsigned)-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 Z7_FORCE_INLINE UInt32 BitStream_Pull(CBitStream *s, unsigned numBits)
{
s->numBits -= numBits;
const 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 Z7_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_64_Int32(v, offset, num, dest) dest = (Int32)((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_Int32(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_Int32(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 ((size_t)(buf - buf_start) * 8 + in.numBits != 64)
return S_FALSE;
if (GetUi64(buf_start) != 0)
return S_FALSE;
return S_OK;
}
HRESULT 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;
if (LzvnMode)
{
if (!outSize || !inSize)
return E_NOTIMPL;
const UInt64 unpackSize = *outSize;
const UInt64 packSize = *inSize;
if (unpackSize > (UInt32)(Int32)-1
|| packSize > (UInt32)(Int32)-1)
return S_FALSE;
RINOK(DecodeLzvn((UInt32)unpackSize, (UInt32)packSize))
}
else
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;
}
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 (outSize)
{
const UInt64 rem = *outSize - pos;
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'
{
UInt32 packSize;
res = GetUInt32(packSize);
if (res == S_OK)
res = DecodeLzvn(cur, packSize);
}
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 ((!LzvnMode && inSize && *inSize != m_InStream.GetProcessedSize())
|| (outSize && *outSize != m_OutWindowStream.GetProcessedSize()))
res = S_FALSE;
return res;
}
Z7_COM7F_IMF(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,63 @@
// LzfseDecoder.h
#ifndef ZIP7_INC_LZFSE_DECODER_H
#define ZIP7_INC_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 {
Z7_CLASS_IMP_NOQIB_1(
CDecoder
, ICompressCoder
)
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, UInt32 packSize);
HRESULT DecodeLzfse(UInt32 unpackSize, Byte version);
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
public:
bool LzvnMode;
CDecoder():
LzvnMode(false)
{}
// sizes are checked in Code()
// UInt64 GetInputProcessedSize() const { return m_InStream.GetProcessedSize(); }
// UInt64 GetOutputProcessedSize() const { return m_OutWindowStream.GetProcessedSize(); }
};
}}
#endif
@@ -0,0 +1,220 @@
// LzhDecoder.cpp
#include "StdAfx.h"
#include "LzhDecoder.h"
namespace NCompress{
namespace NLzh {
namespace NDecoder {
static const UInt32 kWindowSizeMin = 1 << 16;
bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec)
{
_symbolT = -1;
const unsigned n = (unsigned)_inBitStream.ReadBits(numBits);
if (n == 0)
{
const unsigned s = (unsigned)_inBitStream.ReadBits(numBits);
_symbolT = (int)s;
return (s < num);
}
if (n > num)
return false;
{
Byte lens[NPT];
unsigned i;
for (i = 0; i < NPT; i++)
lens[i] = 0;
i = 0;
do
{
unsigned val = (unsigned)_inBitStream.GetValue(16);
unsigned c = val >> 13;
unsigned mov = 3;
if (c == 7)
{
while (val & (1 << 12))
{
val += val;
c++;
}
if (c > 16)
return false;
mov = c - 3;
}
lens[i++] = (Byte)c;
_inBitStream.MovePos(mov);
if ((int)i == spec)
i += _inBitStream.ReadBits(2);
}
while (i < n);
return _decoderT.Build(lens, NHuffman::k_BuildMode_Full);
}
}
static const unsigned NUM_C_BITS = 9;
bool CCoder::ReadC()
{
_symbolC = -1;
const unsigned n = (unsigned)_inBitStream.ReadBits(NUM_C_BITS);
if (n == 0)
{
const unsigned s = (unsigned)_inBitStream.ReadBits(NUM_C_BITS);
_symbolC = (int)s;
return (s < NC);
}
if (n > NC)
return false;
{
Byte lens[NC];
unsigned i = 0;
do
{
unsigned c = (unsigned)_symbolT;
if (_symbolT < 0)
c = _decoderT.DecodeFull(&_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;
return _decoderC.Build(lens, /* n, */ NHuffman::k_BuildMode_Full);
}
}
HRESULT CCoder::CodeReal(UInt32 rem, ICompressProgressInfo *progress)
{
UInt32 blockSize = 0;
while (rem != 0)
{
if (blockSize == 0)
{
if (_inBitStream.ExtraBitsWereRead())
return S_FALSE;
if (progress)
{
const UInt64 packSize = _inBitStream.GetProcessedSize();
const 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;
const unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5);
if (!ReadTP(NP, pbit, -1))
return S_FALSE;
}
blockSize--;
unsigned number = (unsigned)_symbolC;
if (_symbolC < 0)
number = _decoderC.DecodeFull(&_inBitStream);
if (number < 256)
{
_outWindow.PutByte((Byte)number);
rem--;
}
else
{
const unsigned len = number - 256 + kMatchMinLen;
UInt32 dist = (UInt32)(unsigned)_symbolT;
if (_symbolT < 0)
dist = (UInt32)_decoderT.DecodeFull(&_inBitStream);
if (dist > 1)
{
dist--;
dist = ((UInt32)1 << dist) + _inBitStream.ReadBits((unsigned)dist);
}
if (dist >= DictSize)
return S_FALSE;
if (len > rem)
{
// if (FinishMode)
return S_FALSE;
// len = (unsigned)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;
}
HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt32 outSize, ICompressProgressInfo *progress)
{
try
{
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,68 @@
// LzhDecoder.h
#ifndef ZIP7_INC_COMPRESS_LZH_DECODER_H
#define ZIP7_INC_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
{
CLzOutWindow _outWindow;
NBitm::CDecoder<CInBuffer> _inBitStream;
int _symbolT;
int _symbolC;
UInt32 DictSize;
// bool FinishMode;
NHuffman::CDecoder256<NUM_CODE_BITS, NPT, 7> _decoderT;
NHuffman::CDecoder<NUM_CODE_BITS, NC, 10> _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(UInt32 outSize, ICompressProgressInfo *progress);
public:
CCoder(): DictSize(1 << 16)
// , FinishMode(true)
{}
void SetDictSize(UInt32 dictSize) { DictSize = dictSize; }
UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); }
HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
UInt32 outSize, ICompressProgressInfo *progress);
};
}}}
#endif
@@ -0,0 +1,267 @@
// 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 Z7_ST
, _tryMt(1)
, _numThreads(1)
, _memUsage((UInt64)(sizeof(size_t)) << 28)
#endif
{}
CDecoder::~CDecoder()
{
if (_dec)
Lzma2DecMt_Destroy(_dec);
}
Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size)) { _inBufSize = size; return S_OK; }
Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size)) { _outStep = size; return S_OK; }
Z7_COM7F_IMF(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;
}
Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
{
_finishMode = (finishMode != 0);
return S_OK;
}
#ifndef Z7_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;
Z7_COM7F_IMF(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 Z7_ST
{
props.numThreads = 1;
UInt32 numThreads = _numThreads;
if (_tryMt && numThreads >= 1)
{
const UInt64 useLimit = _memUsage;
const UInt32 dictSize = LZMA2_DIC_SIZE_FROM_PROP_FULL(_prop);
const UInt64 expectedBlockSize64 = Get_ExpectedBlockSize_From_Dict(dictSize);
const size_t expectedBlockSize = (size_t)expectedBlockSize64;
const 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);
const 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 Z7_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 Z7_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);
}
Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
{
*value = _inProcessed;
return S_OK;
}
#ifndef Z7_ST
Z7_COM7F_IMF(CDecoder::SetNumberOfThreads(UInt32 numThreads))
{
_numThreads = numThreads;
return S_OK;
}
Z7_COM7F_IMF(CDecoder::SetMemLimit(UInt64 memUsage))
{
_memUsage = memUsage;
return S_OK;
}
#endif
#ifndef Z7_NO_READ_FROM_CODER
Z7_COM7F_IMF(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);
const SRes res = Lzma2DecMt_Init(_dec, _prop, &props, outSize, _finishMode, &_inWrap.vt);
if (res != SZ_OK)
return SResToHRESULT(res);
return S_OK;
}
Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
{ _inStream = inStream; return S_OK; }
Z7_COM7F_IMF(CDecoder::ReleaseInStream())
{ _inStream.Release(); return S_OK; }
Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
size_t size2 = size;
UInt64 inProcessed = 0;
const 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,87 @@
// Lzma2Decoder.h
#ifndef ZIP7_INC_LZMA2_DECODER_H
#define ZIP7_INC_LZMA2_DECODER_H
#include "../../../C/Lzma2DecMt.h"
#include "../Common/CWrappers.h"
namespace NCompress {
namespace NLzma2 {
class CDecoder Z7_final:
public ICompressCoder,
public ICompressSetDecoderProperties2,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public ICompressSetBufSize,
#ifndef Z7_NO_READ_FROM_CODER
public ICompressSetInStream,
public ICompressSetOutStreamSize,
public ISequentialInStream,
#endif
#ifndef Z7_ST
public ICompressSetCoderMt,
public ICompressSetMemLimit,
#endif
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(ICompressCoder)
Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2)
Z7_COM_QI_ENTRY(ICompressSetFinishMode)
Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
Z7_COM_QI_ENTRY(ICompressSetBufSize)
#ifndef Z7_NO_READ_FROM_CODER
Z7_COM_QI_ENTRY(ICompressSetInStream)
Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
Z7_COM_QI_ENTRY(ISequentialInStream)
#endif
#ifndef Z7_ST
Z7_COM_QI_ENTRY(ICompressSetCoderMt)
Z7_COM_QI_ENTRY(ICompressSetMemLimit)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(ICompressCoder)
Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
Z7_IFACE_COM7_IMP(ICompressSetBufSize)
#ifndef Z7_NO_READ_FROM_CODER
Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
Z7_IFACE_COM7_IMP(ICompressSetInStream)
Z7_IFACE_COM7_IMP(ISequentialInStream)
#endif
#ifndef Z7_ST
Z7_IFACE_COM7_IMP(ICompressSetCoderMt)
Z7_IFACE_COM7_IMP(ICompressSetMemLimit)
#endif
CLzma2DecMtHandle _dec;
UInt64 _inProcessed;
Byte _prop;
int _finishMode;
UInt32 _inBufSize;
UInt32 _outStep;
#ifndef Z7_ST
int _tryMt;
UInt32 _numThreads;
UInt64 _memUsage;
#endif
#ifndef Z7_NO_READ_FROM_CODER
CMyComPtr<ISequentialInStream> _inStream;
CSeqInStreamWrap _inWrap;
#endif
public:
CDecoder();
~CDecoder();
};
}}
#endif
@@ -0,0 +1,134 @@
// 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);
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;
case NCoderPropID::kNumThreadGroups:
if (prop.vt != VT_UI4)
return E_INVALIDARG;
// 16-bit value supported by Windows
if (prop.ulVal >= (1u << 16))
return E_INVALIDARG;
lzma2Props.numThreadGroups = (unsigned)prop.ulVal;
break;
default:
RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps))
}
return S_OK;
}
Z7_COM7F_IMF(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));
}
Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
const PROPVARIANT *coderProps, UInt32 numProps))
{
for (UInt32 i = 0; i < numProps; i++)
{
const PROPVARIANT &prop = coderProps[i];
const PROPID propID = propIDs[i];
if (propID == NCoderPropID::kExpectedDataSize)
if (prop.vt == VT_UI8)
Lzma2Enc_SetDataSize(_encoder, prop.uhVal.QuadPart);
}
return S_OK;
}
Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
{
const 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;
Z7_COM7F_IMF(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,30 @@
// Lzma2Encoder.h
#ifndef ZIP7_INC_LZMA2_ENCODER_H
#define ZIP7_INC_LZMA2_ENCODER_H
#include "../../../C/Lzma2Enc.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
namespace NLzma2 {
Z7_CLASS_IMP_COM_4(
CEncoder
, ICompressCoder
, ICompressSetCoderProperties
, ICompressWriteCoderProperties
, ICompressSetCoderPropertiesOpt
)
CLzma2EncHandle _encoder;
public:
CEncoder();
~CEncoder();
};
}}
#endif
@@ -0,0 +1,22 @@
// Lzma2Register.cpp
#include "StdAfx.h"
#include "../Common/RegisterCodec.h"
#include "Lzma2Decoder.h"
#ifndef Z7_EXTRACT_ONLY
#include "Lzma2Encoder.h"
#endif
namespace NCompress {
namespace NLzma2 {
REGISTER_CODEC_E(LZMA2,
CDecoder(),
CEncoder(),
0x21,
"LZMA2")
}}
@@ -0,0 +1,350 @@
// 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;
default: break;
}
return E_FAIL;
}
namespace NCompress {
namespace NLzma {
CDecoder::CDecoder():
FinishStream(false),
_propsWereSet(false),
_outSizeDefined(false),
_outStep(1 << 20),
_inBufSize(0),
_inBufSizeNew(1 << 20),
_lzmaStatus(LZMA_STATUS_NOT_SPECIFIED),
_inBuf(NULL)
{
_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);
}
Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size))
{ _inBufSizeNew = size; return S_OK; }
Z7_COM7F_IMF(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;
}
Z7_COM7F_IMF(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);
}
Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
{
_inProcessed = 0;
_inPos = _inLim = 0;
SetOutStreamSizeResume(outSize);
return S_OK;
}
Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
{
FinishStream = (finishMode != 0);
return S_OK;
}
Z7_COM7F_IMF(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;
const 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)
const bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);
const 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)
{
const 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 SResToHRESULT(res);
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))
}
}
}
Z7_COM7F_IMF(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 Z7_NO_READ_FROM_CODER
Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
{ _inStream = inStream; return S_OK; }
Z7_COM7F_IMF(CDecoder::ReleaseInStream())
{ _inStream.Release(); return S_OK; }
Z7_COM7F_IMF(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;
const 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 ZIP7_INC_LZMA_DECODER_H
#define ZIP7_INC_LZMA_DECODER_H
// #include "../../../C/Alloc.h"
#include "../../../C/LzmaDec.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
namespace NLzma {
class CDecoder Z7_final:
public ICompressCoder,
public ICompressSetDecoderProperties2,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public ICompressSetBufSize,
#ifndef Z7_NO_READ_FROM_CODER
public ICompressSetInStream,
public ICompressSetOutStreamSize,
public ISequentialInStream,
#endif
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(ICompressCoder)
Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2)
Z7_COM_QI_ENTRY(ICompressSetFinishMode)
Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
Z7_COM_QI_ENTRY(ICompressSetBufSize)
#ifndef Z7_NO_READ_FROM_CODER
Z7_COM_QI_ENTRY(ICompressSetInStream)
Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
Z7_COM_QI_ENTRY(ISequentialInStream)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(ICompressCoder)
public:
Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
private:
Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
// Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
Z7_IFACE_COM7_IMP(ICompressSetBufSize)
#ifndef Z7_NO_READ_FROM_CODER
public:
Z7_IFACE_COM7_IMP(ICompressSetInStream)
private:
Z7_IFACE_COM7_IMP(ISequentialInStream)
Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
#else
Z7_COM7F_IMF(SetOutStreamSize(const UInt64 *outSize));
#endif
public:
bool FinishStream; // set it before decoding, if you need to decode full LZMA stream
private:
bool _propsWereSet;
bool _outSizeDefined;
UInt32 _outStep;
UInt32 _inBufSize;
UInt32 _inBufSizeNew;
ELzmaStatus _lzmaStatus;
UInt32 _inPos;
UInt32 _inLim;
Byte *_inBuf;
UInt64 _outSize;
UInt64 _inProcessed;
UInt64 _outProcessed;
// CAlignOffsetAlloc _alloc;
CLzmaDec _state;
HRESULT CreateInputBuffer();
HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
void SetOutStreamSizeResume(const UInt64 *outSize);
#ifndef Z7_NO_READ_FROM_CODER
private:
CMyComPtr<ISequentialInStream> _inStream;
public:
HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize);
#endif
public:
CDecoder();
~CDecoder();
UInt64 GetInputProcessedSize() const { return _inProcessed; }
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,374 @@
// LzmaEncoder.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "../Common/CWrappers.h"
#include "../Common/StreamUtils.h"
#include "LzmaEncoder.h"
// #define LOG_LZMA_THREADS
#ifdef LOG_LZMA_THREADS
#include <stdio.h>
#include "../../Common/IntToString.h"
#include "../../Windows/TimeUtils.h"
EXTERN_C_BEGIN
void LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2]);
EXTERN_C_END
#endif
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 GetLowCharFast(wchar_t c)
{
return c |= 0x20;
}
static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
{
const wchar_t c = GetLowCharFast(*s++);
if (c == 'h')
{
if (GetLowCharFast(*s++) != 'c')
return 0;
const int num = (int)(*s++ - L'0');
if (num < 4 || num > 5)
return 0;
if (*s != 0)
return 0;
*btMode = 0;
*numHashBytes = num;
return 1;
}
if (c != 'b')
return 0;
{
if (GetLowCharFast(*s++) != 't')
return 0;
const int num = (int)(*s++ - L'0');
if (num < 2 || num > 5)
return 0;
if (*s != 0)
return 0;
*btMode = 1;
*numHashBytes = num;
return 1;
}
}
#define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = (int)v; break;
#define SET_PROP_32U(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break;
HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep);
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::kAffinity)
{
if (prop.vt == VT_UI8)
ep.affinity = prop.uhVal.QuadPart;
else
return E_INVALIDARG;
return S_OK;
}
if (propID == NCoderPropID::kAffinityInGroup)
{
if (prop.vt == VT_UI8)
ep.affinityInGroup = prop.uhVal.QuadPart;
else
return E_INVALIDARG;
return S_OK;
}
if (propID == NCoderPropID::kThreadGroup)
{
if (prop.vt == VT_UI4)
ep.affinityGroup = (Int32)(UInt32)prop.ulVal;
else
return E_INVALIDARG;
return S_OK;
}
if (propID == NCoderPropID::kHashBits)
{
if (prop.vt == VT_UI4)
ep.numHashOutBits = prop.ulVal;
else
return E_INVALIDARG;
return S_OK;
}
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 (propID == NCoderPropID::kDictionarySize)
{
if (prop.vt == VT_UI8)
{
// 21.03 : we support 64-bit VT_UI8 for dictionary and (dict == 4 GiB)
const UInt64 v = prop.uhVal.QuadPart;
if (v > ((UInt64)1 << 32))
return E_INVALIDARG;
UInt32 dict;
if (v == ((UInt64)1 << 32))
dict = (UInt32)(Int32)-1;
else
dict = (UInt32)v;
ep.dictSize = dict;
return S_OK;
}
}
if (prop.vt != VT_UI4)
return E_INVALIDARG;
const UInt32 v = prop.ulVal;
switch (propID)
{
case NCoderPropID::kDefaultProp:
if (v > 32)
return E_INVALIDARG;
ep.dictSize = (v == 32) ? (UInt32)(Int32)-1 : (UInt32)1 << (unsigned)v;
break;
SET_PROP_32(kLevel, level)
SET_PROP_32(kNumFastBytes, fb)
SET_PROP_32U(kMatchFinderCycles, mc)
SET_PROP_32(kAlgorithm, algo)
SET_PROP_32U(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;
}
Z7_COM7F_IMF(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];
const 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));
}
Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
const PROPVARIANT *coderProps, UInt32 numProps))
{
for (UInt32 i = 0; i < numProps; i++)
{
const PROPVARIANT &prop = coderProps[i];
const PROPID propID = propIDs[i];
if (propID == NCoderPropID::kExpectedDataSize)
if (prop.vt == VT_UI8)
LzmaEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
}
return S_OK;
}
Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
{
Byte props[LZMA_PROPS_SIZE];
SizeT 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;
#ifdef LOG_LZMA_THREADS
static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ')
{
char temp[64];
char *p = temp + 32;
ConvertUInt64ToString(val, p);
unsigned len = (unsigned)strlen(p);
for (; len < numDigits; len++)
*--p = c;
printf("%s", p);
}
static void PrintTime(const char *s, UInt64 val, UInt64 total)
{
printf(" %s :", s);
const UInt32 kFreq = 10000000;
UInt64 sec = val / kFreq;
PrintNum(sec, 6);
printf(" .");
UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000);
PrintNum(ms, 3, '0');
while (val > ((UInt64)1 << 56))
{
val >>= 1;
total >>= 1;
}
UInt64 percent = 0;
if (total != 0)
percent = val * 100 / total;
printf(" =");
PrintNum(percent, 4);
printf("%%");
}
struct CBaseStat
{
UInt64 kernelTime, userTime;
BOOL Get(HANDLE thread, const CBaseStat *prevStat)
{
FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT;
BOOL res = GetThreadTimes(thread
, &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT);
if (res)
{
kernelTime = GetTime64(kernelTimeFT);
userTime = GetTime64(userTimeFT);
if (prevStat)
{
kernelTime -= prevStat->kernelTime;
userTime -= prevStat->userTime;
}
}
return res;
}
};
static void PrintStat(HANDLE thread, UInt64 totalTime, const CBaseStat *prevStat)
{
CBaseStat newStat;
if (!newStat.Get(thread, prevStat))
return;
PrintTime("K", newStat.kernelTime, totalTime);
const UInt64 processTime = newStat.kernelTime + newStat.userTime;
PrintTime("U", newStat.userTime, totalTime);
PrintTime("S", processTime, totalTime);
printf("\n");
// PrintTime("G ", totalTime, totalTime);
}
#endif
Z7_COM7F_IMF(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);
#ifdef LOG_LZMA_THREADS
FILETIME startTimeFT;
NWindows::NTime::GetCurUtcFileTime(startTimeFT);
UInt64 totalTime = GetTime64(startTimeFT);
CBaseStat oldStat;
if (!oldStat.Get(GetCurrentThread(), NULL))
return E_FAIL;
#endif
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)
#ifdef LOG_LZMA_THREADS
NWindows::NTime::GetCurUtcFileTime(startTimeFT);
totalTime = GetTime64(startTimeFT) - totalTime;
HANDLE lz_threads[2];
LzmaEnc_GetLzThreads(_encoder, lz_threads);
printf("\n");
printf("Main: "); PrintStat(GetCurrentThread(), totalTime, &oldStat);
printf("Hash: "); PrintStat(lz_threads[0], totalTime, NULL);
printf("BinT: "); PrintStat(lz_threads[1], totalTime, NULL);
// PrintTime("Total: ", totalTime, totalTime);
printf("\n");
#endif
return SResToHRESULT(res);
}
}}
@@ -0,0 +1,45 @@
// LzmaEncoder.h
#ifndef ZIP7_INC_LZMA_ENCODER_H
#define ZIP7_INC_LZMA_ENCODER_H
#include "../../../C/LzmaEnc.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
namespace NLzma {
class CEncoder Z7_final:
public ICompressCoder,
public ICompressSetCoderProperties,
public ICompressWriteCoderProperties,
public ICompressSetCoderPropertiesOpt,
public CMyUnknownImp
{
Z7_COM_UNKNOWN_IMP_4(
ICompressCoder,
ICompressSetCoderProperties,
ICompressWriteCoderProperties,
ICompressSetCoderPropertiesOpt)
Z7_IFACE_COM7_IMP(ICompressCoder)
public:
Z7_IFACE_COM7_IMP(ICompressSetCoderProperties)
Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties)
Z7_IFACE_COM7_IMP(ICompressSetCoderPropertiesOpt)
CLzmaEncHandle _encoder;
UInt64 _inputProcessed;
CEncoder();
~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 Z7_EXTRACT_ONLY
#include "LzmaEncoder.h"
#endif
namespace NCompress {
namespace NLzma {
REGISTER_CODEC_E(LZMA,
CDecoder(),
CEncoder(),
0x30101,
"LZMA")
}}
@@ -0,0 +1,619 @@
// 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 {
class CBitDecoder
{
public:
const Byte *_buf;
unsigned _bitPos;
void Init(const Byte *buf, size_t size) throw()
{
_buf = buf + size;
_bitPos = 0;
}
Z7_FORCE_INLINE
UInt32 GetValue(unsigned numBits) const
{
UInt32 v =
((UInt32)_buf[-1] << 16) |
((UInt32)_buf[-2] << 8) |
(UInt32)_buf[-3];
v >>= 24 - numBits - _bitPos;
return v & ((1u << numBits) - 1);
}
Z7_FORCE_INLINE
UInt32 GetValue_InHigh32bits()
{
return GetUi32(_buf - 4) << _bitPos;
}
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;
}
};
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 (;;)
{
const 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 (;;)
{
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;
const Byte b = p[0];
if ((b & 0x80) == 0) // REX (0x48 or 0x4c)
{
const unsigned b2 = p[2] - 0x5; // [RIP + disp32]
if (b2 & 0x7)
continue;
if (p[1] != 0x8d) // LEA
{
if (p[1] != 0x8b || b != 0x48 || (b2 & 0xf7))
continue;
// MOV RAX / RCX, [RIP + disp32]
}
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;
{
Byte *p2 = p + codeLen;
UInt32 n = GetUi32(p2);
if (i - last_x86_pos <= maxTransOffset)
{
n = (UInt32)((Int32)n - i);
SetUi32(p2, n)
}
target = history + (((UInt32)i + n) & 0xFFFF);
}
i += (Int32)(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)
{
unsigned 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)
{
unsigned number;
HUFF_DEC(number, m_PosDecoder)
LIMIT_CHECK
const 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;
}
}
}
unsigned lenSlot;
HUFF_DEC(lenSlot, m_LenDecoder)
LIMIT_CHECK
UInt32 len = g_LenBases[lenSlot];
{
const 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;
unsigned power;
UInt32 distance32;
if (_rc.Decode(&deltaRepStates[0], k_NumRepProbs, deltaRepProbs[0]) == 0)
{
HUFF_DEC(power, m_PowerDecoder)
LIMIT_CHECK
unsigned number;
HUFF_DEC(number, m_DeltaDecoder)
LIMIT_CHECK
const 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);
}
const UInt32 dist = (distance32 << power);
unsigned lenSlot;
HUFF_DEC(lenSlot, m_LenDecoder)
LIMIT_CHECK
UInt32 len = g_LenBases[lenSlot];
{
const 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,209 @@
// LzmsDecoder.h
// The code is based on LZMS description from wimlib code
#ifndef ZIP7_INC_LZMS_DECODER_H
#define ZIP7_INC_LZMS_DECODER_H
#include "../../../C/CpuArch.h"
#include "../../../C/HuffEnc.h"
#include "HuffmanDecoder.h"
namespace NCompress {
namespace NLzms {
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->Build(levels, /* NumSyms, */ NHuffman::k_BuildMode_Full);
}
void Rebuild() throw()
{
Generate();
RebuildRem = m_RebuildFreq;
const 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 += (UInt32)((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);
const UInt32 prob = entry->GetProb();
if (range <= 0xFFFF)
{
range <<= 16;
code <<= 16;
// if (cur >= end) throw 1;
code |= GetUi16(cur);
cur += 2;
}
const 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;
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);
size_t GetUnpackSize() const { return _pos; }
};
}}
#endif
+61
View File
@@ -0,0 +1,61 @@
// Lzx.h
#ifndef ZIP7_INC_COMPRESS_LZX_H
#define ZIP7_INC_COMPRESS_LZX_H
#include "../../Common/MyTypes.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;
// const unsigned kNumPowerPosSlots = (kNumLinearPosSlotBits + 1) * 2; // non-including two first linear slots.
const unsigned kNumPowerPosSlots = (kNumLinearPosSlotBits + 2) * 2; // including two first linear slots.
}}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,106 @@
// LzxDecoder.h
#ifndef ZIP7_INC_LZX_DECODER_H
#define ZIP7_INC_LZX_DECODER_H
#include "HuffmanDecoder.h"
#include "Lzx.h"
namespace NCompress {
namespace NLzx {
const unsigned kAdditionalOutputBufSize = 32 * 2;
const unsigned kNumTableBits_Main = 11;
const unsigned kNumTableBits_Len = 8;
// if (kNumLenSymols_Big <= 256) we can use NHuffman::CDecoder256
// if (kNumLenSymols_Big > 256) we must use NHuffman::CDecoder
// const unsigned kNumLenSymols_Big_Start = kNumLenSlots - 1 + kMatchMinLen; // 8 - 1 + 2
const unsigned kNumLenSymols_Big_Start = 0;
// const unsigned kNumLenSymols_Big_Start = 0;
const unsigned kNumLenSymols_Big = kNumLenSymols_Big_Start + kNumLenSymbols;
#if 1
// for smallest structure size:
const unsigned kPosSlotOffset = 0;
#else
// use virtual entries for mispredicted branches:
const unsigned kPosSlotOffset = 256 / kNumLenSlots;
#endif
class CBitByteDecoder;
class CDecoder
{
public:
UInt32 _pos;
UInt32 _winSize;
Byte *_win;
bool _overDict;
bool _isUncompressedBlock;
bool _skipByte;
bool _keepHistory;
bool _keepHistoryForNext;
bool _needAlloc;
bool _wimMode;
Byte _numDictBits;
// unsigned _numAlignBits_PosSlots;
// unsigned _numAlignBits;
UInt32 _numAlignBits_Dist;
private:
unsigned _numPosLenSlots;
UInt32 _unpackBlockSize;
UInt32 _writePos;
UInt32 _x86_translationSize;
UInt32 _x86_processedSize;
Byte *_x86_buf;
Byte *_unpackedData;
public:
Byte _extra[kPosSlotOffset + kNumPosSlots];
UInt32 _reps[kPosSlotOffset + kNumPosSlots];
NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize, kNumTableBits_Main> _mainDecoder;
NHuffman::CDecoder256<kNumHuffmanBits, kNumLenSymols_Big, kNumTableBits_Len> _lenDecoder;
NHuffman::CDecoder7b<kAlignTableSize> _alignDecoder;
private:
Byte _mainLevels[kMainTableSize];
Byte _lenLevels[kNumLenSymols_Big];
HRESULT Flush() throw();
bool ReadTables(CBitByteDecoder &_bitStream) throw();
HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize) throw();
HRESULT SetParams2(unsigned numDictBits) throw();
public:
CDecoder() throw();
~CDecoder() throw();
void Set_WimMode(bool wimMode) { _wimMode = wimMode; }
void Set_KeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
void Set_KeepHistoryForNext(bool keepHistoryForNext) { _keepHistoryForNext = keepHistoryForNext; }
HRESULT Set_ExternalWindow_DictBits(Byte *win, unsigned numDictBits)
{
_needAlloc = false;
_win = win;
_winSize = (UInt32)1 << numDictBits;
return SetParams2(numDictBits);
}
HRESULT Set_DictBits_and_Alloc(unsigned numDictBits) throw();
HRESULT Code_WithExceedReadWrite(const Byte *inData, size_t inSize, UInt32 outSize) throw();
bool WasBlockFinished() const { return _unpackBlockSize == 0; }
const Byte *GetUnpackData() const { return _unpackedData; }
UInt32 GetUnpackSize() const { return _pos - _writePos; }
};
}}
#endif
+225
View File
@@ -0,0 +1,225 @@
// Mtf8.h
#ifndef ZIP7_INC_COMPRESS_MTF8_H
#define ZIP7_INC_COMPRESS_MTF8_H
#include "../../../C/CpuArch.h"
namespace NCompress {
struct CMtf8Encoder
{
Byte Buf[256];
unsigned FindAndMove(Byte v) throw()
{
#if 1
Byte b = Buf[0];
if (v == b)
return 0;
Buf[0] = v;
for (unsigned pos = 0;;)
{
Byte a;
a = Buf[++pos]; Buf[pos] = b; if (v == a) return pos;
b = Buf[++pos]; Buf[pos] = a; if (v == b) return pos;
}
#else
size_t pos;
for (pos = 0; Buf[pos] != v; pos++);
const 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;
#endif
}
};
/*
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 Z7_MTF_MOVS 3
#else
typedef UInt32 CMtfVar;
#define Z7_MTF_MOVS 2
#endif
#define Z7_MTF_MASK ((1 << Z7_MTF_MOVS) - 1)
struct CMtf8Decoder
{
CMtfVar Buf[256 >> Z7_MTF_MOVS];
void StartInit() { memset(Buf, 0, sizeof(Buf)); }
void Add(unsigned pos, Byte val) { Buf[pos >> Z7_MTF_MOVS] |= ((CMtfVar)val << ((pos & Z7_MTF_MASK) << 3)); }
Byte GetHead() const { return (Byte)Buf[0]; }
Z7_FORCE_INLINE
Byte GetAndMove(unsigned pos) throw()
{
const UInt32 lim = ((UInt32)pos >> Z7_MTF_MOVS);
pos = (pos & Z7_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 >> (Z7_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 >> (Z7_MTF_MASK << 3));
prev = (n1 >> (Z7_MTF_MASK << 3));
}
*/
for (; i < lim; i++)
{
const CMtfVar n0 = Buf[i];
Buf[i ] = (n0 << 8) | prev;
prev = (n0 >> (Z7_MTF_MASK << 3));
}
const CMtfVar next = Buf[i];
const 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,219 @@
// PpmdDecoder.cpp
#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 << 16);
enum
{
kStatus_NeedInit,
kStatus_Normal,
kStatus_Finished_With_Mark,
kStatus_Error
};
CDecoder::~CDecoder()
{
::MidFree(_outBuf);
Ppmd7_Free(&_ppmd, &g_BigAlloc);
}
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size))
{
if (size < 5)
return E_INVALIDARG;
_order = props[0];
const 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;
}
#define MY_rangeDec _ppmd.rc.dec
#define CHECK_EXTRA_ERROR \
if (_inStream.Extra) { \
_status = kStatus_Error; \
return (_res = (_inStream.Res != SZ_OK ? _inStream.Res: S_FALSE)); }
HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
{
if (_res != S_OK)
return _res;
switch (_status)
{
case kStatus_Finished_With_Mark: return S_OK;
case kStatus_Error: return S_FALSE;
case kStatus_NeedInit:
_inStream.Init();
if (!Ppmd7z_RangeDec_Init(&MY_rangeDec))
{
_status = kStatus_Error;
return (_res = S_FALSE);
}
CHECK_EXTRA_ERROR
_status = kStatus_Normal;
Ppmd7_Init(&_ppmd, _order);
break;
default: break;
}
if (_outSizeDefined)
{
const UInt64 rem = _outSize - _processedSize;
if (size > rem)
size = (UInt32)rem;
}
int sym = 0;
{
Byte *buf = memStream;
const Byte *lim = buf + size;
for (; buf != lim; buf++)
{
sym = Ppmd7z_DecodeSymbol(&_ppmd);
if (_inStream.Extra || sym < 0)
break;
*buf = (Byte)sym;
}
/*
buf = Ppmd7z_DecodeSymbols(&_ppmd, buf, lim);
sym = _ppmd.LastSymbol;
*/
_processedSize += (size_t)(buf - memStream);
}
CHECK_EXTRA_ERROR
if (sym >= 0)
{
if (!FinishStream
|| !_outSizeDefined
|| _outSize != _processedSize
|| MY_rangeDec.Code == 0)
return S_OK;
/*
// We can decode additional End Marker here:
sym = Ppmd7z_DecodeSymbol(&_ppmd);
CHECK_EXTRA_ERROR
*/
}
if (sym != PPMD7_SYM_END || MY_rangeDec.Code != 0)
{
_status = kStatus_Error;
return (_res = S_FALSE);
}
_status = kStatus_Finished_With_Mark;
return S_OK;
}
Z7_COM7F_IMF(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;
const HRESULT res = CodeSpec(_outBuf, kBufSize);
const size_t processed = (size_t)(_processedSize - startPos);
RINOK(WriteStream(outStream, _outBuf, processed))
RINOK(res)
if (_status == kStatus_Finished_With_Mark)
break;
if (progress)
{
const UInt64 inProcessed = _inStream.GetProcessed();
RINOK(progress->SetRatioInfo(&inProcessed, &_processedSize))
}
}
while (!_outSizeDefined || _processedSize < _outSize);
if (FinishStream && inSize && *inSize != _inStream.GetProcessed())
return S_FALSE;
return S_OK;
}
Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
{
_outSizeDefined = (outSize != NULL);
if (_outSizeDefined)
_outSize = *outSize;
_processedSize = 0;
_status = kStatus_NeedInit;
_res = SZ_OK;
return S_OK;
}
Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
{
FinishStream = (finishMode != 0);
return S_OK;
}
Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
{
*value = _inStream.GetProcessed();
return S_OK;
}
#ifndef Z7_NO_READ_FROM_CODER
Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
{
InSeqStream = inStream;
_inStream.Stream = inStream;
return S_OK;
}
Z7_COM7F_IMF(CDecoder::ReleaseInStream())
{
InSeqStream.Release();
return S_OK;
}
Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
{
const UInt64 startPos = _processedSize;
const HRESULT res = CodeSpec((Byte *)data, size);
if (processedSize)
*processedSize = (UInt32)(_processedSize - startPos);
return res;
}
#endif
}}
@@ -0,0 +1,87 @@
// PpmdDecoder.h
#ifndef ZIP7_INC_COMPRESS_PPMD_DECODER_H
#define ZIP7_INC_COMPRESS_PPMD_DECODER_H
#include "../../../C/Ppmd7.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "../Common/CWrappers.h"
namespace NCompress {
namespace NPpmd {
class CDecoder Z7_final:
public ICompressCoder,
public ICompressSetDecoderProperties2,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
#ifndef Z7_NO_READ_FROM_CODER
public ICompressSetInStream,
public ICompressSetOutStreamSize,
public ISequentialInStream,
#endif
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(ICompressCoder)
Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2)
Z7_COM_QI_ENTRY(ICompressSetFinishMode)
Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
#ifndef Z7_NO_READ_FROM_CODER
Z7_COM_QI_ENTRY(ICompressSetInStream)
Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
Z7_COM_QI_ENTRY(ISequentialInStream)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(ICompressCoder)
Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
#ifndef Z7_NO_READ_FROM_CODER
Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
Z7_IFACE_COM7_IMP(ICompressSetInStream)
Z7_IFACE_COM7_IMP(ISequentialInStream)
#else
Z7_COM7F_IMF(SetOutStreamSize(const UInt64 *outSize));
#endif
Byte *_outBuf;
CByteInBufWrap _inStream;
CPpmd7 _ppmd;
Byte _order;
bool FinishStream;
bool _outSizeDefined;
HRESULT _res;
int _status;
UInt64 _outSize;
UInt64 _processedSize;
HRESULT CodeSpec(Byte *memStream, UInt32 size);
public:
#ifndef Z7_NO_READ_FROM_CODER
CMyComPtr<ISequentialInStream> InSeqStream;
#endif
CDecoder():
_outBuf(NULL),
FinishStream(false),
_outSizeDefined(false)
{
Ppmd7_Construct(&_ppmd);
_ppmd.rc.dec.Stream = &_inStream.vt;
}
~CDecoder();
};
}}
#endif
@@ -0,0 +1,193 @@
// PpmdEncoder.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.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 = (UInt32)1 << (level + 19);
const unsigned kMult = 16;
if (MemSize / kMult > ReduceSize)
{
for (unsigned i = 16; i < 32; 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);
Ppmd7_Construct(&_ppmd);
_ppmd.rc.enc.Stream = &_outStream.vt;
}
CEncoder::~CEncoder()
{
::MidFree(_inBuf);
Ppmd7_Free(&_ppmd, &g_BigAlloc);
}
Z7_COM7F_IMF(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];
const 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 (propID == NCoderPropID::kUsedMemorySize)
{
// here we have selected (4 GiB - 1 KiB) as replacement for (4 GiB) MEM_SIZE.
const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10);
UInt32 v;
if (prop.vt == VT_UI8)
{
// 21.03 : we support 64-bit values (for 4 GiB value)
const UInt64 v64 = prop.uhVal.QuadPart;
if (v64 > ((UInt64)1 << 32))
return E_INVALIDARG;
if (v64 == ((UInt64)1 << 32))
v = kPpmd_Default_4g;
else
v = (UInt32)v64;
}
else if (prop.vt == VT_UI4)
v = (UInt32)prop.ulVal;
else
return E_INVALIDARG;
if (v > PPMD7_MAX_MEM_SIZE)
v = kPpmd_Default_4g;
/* here we restrict MEM_SIZE for Encoder.
It's for better performance of encoding and decoding.
The Decoder still supports more MEM_SIZE values. */
if (v < ((UInt32)1 << 16) || (v & 3) != 0)
return E_INVALIDARG;
// if (v < PPMD7_MIN_MEM_SIZE) return E_INVALIDARG; // (1 << 11)
/*
Supported MEM_SIZE range :
[ (1 << 11) , 0xFFFFFFFF - 12 * 3 ] - current 7-Zip's Ppmd7 constants
[ 1824 , 0xFFFFFFFF ] - real limits of Ppmd7 code
*/
props.MemSize = v;
continue;
}
if (prop.vt != VT_UI4)
return E_INVALIDARG;
const UInt32 v = (UInt32)prop.ulVal;
switch (propID)
{
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;
}
Z7_COM7F_IMF(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);
}
Z7_COM7F_IMF(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_Init_RangeEnc(&_ppmd);
Ppmd7_Init(&_ppmd, (unsigned)_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.
// Ppmd7z_EncodeSymbol(&_ppmd, -1);
Ppmd7z_Flush_RangeEnc(&_ppmd);
return _outStream.Flush();
}
const Byte *buf = _inBuf;
const Byte *lim = buf + size;
/*
for (; buf < lim; buf++)
{
Ppmd7z_EncodeSymbol(&_ppmd, *buf);
RINOK(_outStream.Res);
}
*/
Ppmd7z_EncodeSymbols(&_ppmd, buf, lim);
RINOK(_outStream.Res)
processed += size;
if (progress)
{
const UInt64 outSize = _outStream.GetProcessed();
RINOK(progress->SetRatioInfo(&processed, &outSize))
}
}
}
}}
@@ -0,0 +1,49 @@
// PpmdEncoder.h
#ifndef ZIP7_INC_COMPRESS_PPMD_ENCODER_H
#define ZIP7_INC_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);
};
Z7_CLASS_IMP_COM_3(
CEncoder
, ICompressCoder
, ICompressSetCoderProperties
, ICompressWriteCoderProperties
)
Byte *_inBuf;
CByteOutBufWrap _outStream;
CPpmd7 _ppmd;
CEncProps _props;
public:
CEncoder();
~CEncoder();
};
}}
#endif
@@ -0,0 +1,22 @@
// PpmdRegister.cpp
#include "StdAfx.h"
#include "../Common/RegisterCodec.h"
#include "PpmdDecoder.h"
#ifndef Z7_EXTRACT_ONLY
#include "PpmdEncoder.h"
#endif
namespace NCompress {
namespace NPpmd {
REGISTER_CODEC_E(PPMD,
CDecoder(),
CEncoder(),
0x30401,
"PPMD")
}}
@@ -0,0 +1,309 @@
// PpmdZip.cpp
#include "StdAfx.h"
#include "../../../C/CpuArch.h"
#include "../Common/RegisterCodec.h"
#include "../Common/StreamUtils.h"
#include "PpmdZip.h"
namespace NCompress {
namespace NPpmdZip {
static const UInt32 kBufSize = 1 << 20;
bool CBuf::Alloc()
{
if (!Buf)
Buf = (Byte *)::MidAlloc(kBufSize);
return (Buf != NULL);
}
CDecoder::CDecoder(bool fullFileMode):
_fullFileMode(fullFileMode)
{
Ppmd8_Construct(&_ppmd);
_ppmd.Stream.In = &_inStream.vt;
}
CDecoder::~CDecoder()
{
Ppmd8_Free(&_ppmd, &g_BigAlloc);
}
Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
{
// try {
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;
const UInt32 val = GetUi16(buf);
const unsigned order = (val & 0xF) + 1;
const UInt32 mem = ((val >> 4) & 0xFF) + 1;
const unsigned 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_Init_RangeDec(&_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;
}
}
int sym;
Byte *buf = _outStream.Buf;
const Byte *lim = buf + size;
do
{
sym = Ppmd8_DecodeSymbol(&_ppmd);
if (_inStream.Extra || sym < 0)
break;
*buf++ = (Byte)sym;
}
while (buf != lim);
const size_t cur = (size_t)(buf - _outStream.Buf);
processedSize += cur;
RINOK(WriteStream(outStream, _outStream.Buf, cur))
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)
{
const 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;
// } catch (...) { return E_FAIL; }
}
Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
{
_fullFileMode = (finishMode != 0);
return S_OK;
}
Z7_COM7F_IMF(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 - 1);
const unsigned kMult = 16;
for (UInt32 m = 1; m < MemSizeMB; m <<= 1)
if (ReduceSize <= (m << 20) / kMult)
{
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);
}
Z7_COM7F_IMF(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];
const PROPID propID = propIDs[i];
if (propID > NCoderPropID::kReduceSize)
continue;
if (propID == NCoderPropID::kReduceSize)
{
props.ReduceSize = (UInt32)(Int32)-1;
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;
const 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 >= PPMD8_RESTORE_METHOD_UNSUPPPORTED)
return E_INVALIDARG;
props.Restor = (int)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);
}
Z7_COM7F_IMF(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_Init_RangeEnc(&_ppmd)
Ppmd8_Init(&_ppmd, (unsigned)_props.Order, (unsigned)_props.Restor);
{
const unsigned val =
((unsigned)_props.Order - 1)
+ (((unsigned)_props.MemSizeMB - 1) << 4)
+ ((unsigned)_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_Flush_RangeEnc(&_ppmd);
return _outStream.Flush();
}
processed += size;
const Byte *buf = _inStream.Buf;
const Byte *lim = buf + size;
do
{
Ppmd8_EncodeSymbol(&_ppmd, *buf);
if (_outStream.Res != S_OK)
break;
}
while (++buf != lim);
RINOK(_outStream.Res)
if (progress)
{
const UInt64 outProccessed = _outStream.GetProcessed();
RINOK(progress->SetRatioInfo(&processed, &outProccessed))
}
}
}
}}
@@ -0,0 +1,78 @@
// PpmdZip.h
#ifndef ZIP7_INC_COMPRESS_PPMD_ZIP_H
#define ZIP7_INC_COMPRESS_PPMD_ZIP_H
#include "../../../C/Alloc.h"
#include "../../../C/Ppmd8.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "../Common/CWrappers.h"
namespace NCompress {
namespace NPpmdZip {
struct CBuf
{
Byte *Buf;
CBuf(): Buf(NULL) {}
~CBuf() { ::MidFree(Buf); }
bool Alloc();
};
Z7_CLASS_IMP_NOQIB_3(
CDecoder
, ICompressCoder
, ICompressSetFinishMode
, ICompressGetInStreamProcessedSize
)
bool _fullFileMode;
CByteInBufWrap _inStream;
CBuf _outStream;
CPpmd8 _ppmd;
public:
CDecoder(bool fullFileMode = true);
~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);
};
Z7_CLASS_IMP_NOQIB_2(
CEncoder
, ICompressCoder
, ICompressSetCoderProperties
)
CByteOutBufWrap _outStream;
CBuf _inStream;
CPpmd8 _ppmd;
CEncProps _props;
public:
CEncoder();
~CEncoder();
};
}}
#endif
@@ -0,0 +1,355 @@
// QuantumDecoder.cpp
#include "StdAfx.h"
// #include <stdio.h>
#include "../../../C/Alloc.h"
#include "../../../C/CpuArch.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 kNumSimpleLenSlots = 6;
static const unsigned kUpdateStep = 8;
static const unsigned kFreqSumMax = 3800;
static const unsigned kReorderCount_Start = 4;
static const unsigned kReorderCount = 50;
class CRangeDecoder
{
UInt32 Low;
UInt32 Range;
UInt32 Code;
unsigned _bitOffset;
const Byte *_buf;
const Byte *_bufLim;
public:
Z7_FORCE_INLINE
void Init(const Byte *inData, size_t inSize)
{
Code = ((UInt32)*inData << 8) | inData[1];
_buf = inData + 2;
_bufLim = inData + inSize;
_bitOffset = 0;
Low = 0;
Range = 0x10000;
}
Z7_FORCE_INLINE
bool WasExtraRead() const
{
return _buf > _bufLim;
}
Z7_FORCE_INLINE
UInt32 ReadBits(unsigned numBits) // numBits > 0
{
unsigned bitOffset = _bitOffset;
const Byte *buf = _buf;
const UInt32 res = GetBe32(buf) << bitOffset;
bitOffset += numBits;
_buf = buf + (bitOffset >> 3);
_bitOffset = bitOffset & 7;
return res >> (32 - numBits);
}
// ---------- Range Decoder functions ----------
Z7_FORCE_INLINE
bool Finish()
{
const unsigned numBits = 2 + ((16 - 2 - _bitOffset) & 7);
if (ReadBits(numBits) != 0)
return false;
return _buf == _bufLim;
}
Z7_FORCE_INLINE
UInt32 GetThreshold(UInt32 total) const
{
return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required;
}
Z7_FORCE_INLINE
void Decode(UInt32 start, UInt32 end, UInt32 total)
{
// UInt32 hi = ~(Low + end * Range / total - 1);
UInt32 hi = 0 - (Low + end * Range / total);
const UInt32 offset = start * Range / total;
UInt32 lo = Low + offset;
Code -= offset;
UInt32 numBits = 0;
lo ^= hi;
while (lo & (1u << 15))
{
lo <<= 1;
hi <<= 1;
numBits++;
}
lo ^= hi;
UInt32 an = lo & hi;
while (an & (1u << 14))
{
an <<= 1;
lo <<= 1;
hi <<= 1;
numBits++;
}
Low = lo;
Range = ((~hi - lo) & 0xffff) + 1;
if (numBits)
Code = (Code << numBits) + ReadBits(numBits);
}
};
// Z7_FORCE_INLINE
Z7_NO_INLINE
unsigned CModelDecoder::Decode(CRangeDecoder *rc)
// Z7_NO_INLINE void CModelDecoder::Normalize()
{
if (Freqs[0] > kFreqSumMax)
{
if (--ReorderCount == 0)
{
ReorderCount = kReorderCount;
{
unsigned i = NumItems;
unsigned next = 0;
UInt16 *freqs = &Freqs[i];
do
{
const unsigned freq = *--freqs;
*freqs = (UInt16)((freq - next + 1) >> 1);
next = freq;
}
while (--i);
}
{
for (unsigned i = 0; i < NumItems - 1; i++)
{
UInt16 freq = Freqs[i];
for (unsigned k = i + 1; k < NumItems; k++)
if (freq < Freqs[k])
{
const UInt16 freq2 = Freqs[k];
Freqs[k] = freq;
Freqs[i] = freq2;
freq = freq2;
const Byte val = Vals[i];
Vals[i] = Vals[k];
Vals[k] = val;
}
}
}
unsigned i = NumItems;
unsigned freq = 0;
UInt16 *freqs = &Freqs[i];
do
{
freq += *--freqs;
*freqs = (UInt16)freq;
}
while (--i);
}
else
{
unsigned i = NumItems;
unsigned next = 1;
UInt16 *freqs = &Freqs[i];
do
{
unsigned freq = *--freqs >> 1;
if (freq < next)
freq = next;
*freqs = (UInt16)freq;
next = freq + 1;
}
while (--i);
}
}
unsigned res;
{
const unsigned freq0 = Freqs[0];
Freqs[0] = (UInt16)(freq0 + kUpdateStep);
const unsigned threshold = rc->GetThreshold(freq0);
UInt16 *freqs = &Freqs[1];
unsigned freq = *freqs;
while (freq > threshold)
{
*freqs++ = (UInt16)(freq + kUpdateStep);
freq = *freqs;
}
res = Vals[freqs - Freqs - 1];
rc->Decode(freq, freqs[-1] - kUpdateStep, freq0);
}
return res;
}
Z7_NO_INLINE
void CModelDecoder::Init(unsigned numItems, unsigned startVal)
{
NumItems = numItems;
ReorderCount = kReorderCount_Start;
UInt16 *freqs = Freqs;
freqs[numItems] = 0;
Byte *vals = Vals;
do
{
*freqs++ = (UInt16)numItems;
*vals++ = (Byte)startVal;
startVal++;
}
while (--numItems);
}
HRESULT CDecoder::Code(const Byte *inData, size_t inSize, UInt32 outSize, bool keepHistory)
{
if (inSize < 2)
return S_FALSE;
if (!keepHistory)
{
_winPos = 0;
m_Selector.Init(kNumSelectors, 0);
unsigned i;
for (i = 0; i < kNumLitSelectors; i++)
m_Literals[i].Init(kNumLitSymbols, i * kNumLitSymbols);
const unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1));
// const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 };
for (i = 0; i < kNumMatchSelectors; i++)
{
const unsigned num = 24 + i * 6 + ((i + 1) & 2) * 3;
m_PosSlot[i].Init(MyMin(numItems, num), 0);
}
m_LenSlot.Init(kNumLenSymbols, kMatchMinLen + kNumMatchSelectors - 1);
}
CRangeDecoder rc;
rc.Init(inData, inSize);
const UInt32 winSize = _winSize;
Byte *pos;
{
UInt32 winPos = _winPos;
if (winPos == winSize)
{
winPos = 0;
_winPos = winPos;
_overWin = true;
}
if (outSize > winSize - winPos)
return S_FALSE;
pos = _win + winPos;
}
while (outSize != 0)
{
if (rc.WasExtraRead())
return S_FALSE;
const unsigned selector = m_Selector.Decode(&rc);
if (selector < kNumLitSelectors)
{
const unsigned b = m_Literals[selector].Decode(&rc);
*pos++ = (Byte)b;
--outSize;
// if (--outSize == 0) break;
}
else
{
unsigned len = selector - kNumLitSelectors + kMatchMinLen;
if (selector == kNumLitSelectors + kNumMatchSelectors - 1)
{
len = m_LenSlot.Decode(&rc);
if (len >= kNumSimpleLenSlots + kMatchMinLen + kNumMatchSelectors - 1)
{
len -= kNumSimpleLenSlots - 4 + kMatchMinLen + kNumMatchSelectors - 1;
const unsigned numDirectBits = (unsigned)(len >> 2);
len = ((4 | (len & 3)) << numDirectBits) - (4 << 1)
+ kNumSimpleLenSlots
+ kMatchMinLen + kNumMatchSelectors - 1;
if (numDirectBits < 6)
len += rc.ReadBits(numDirectBits);
}
}
UInt32 dist = m_PosSlot[(size_t)selector - kNumLitSelectors].Decode(&rc);
if (dist >= 4)
{
const unsigned numDirectBits = (unsigned)((dist >> 1) - 1);
dist = ((2 | (dist & 1)) << numDirectBits) + rc.ReadBits(numDirectBits);
}
if ((Int32)(outSize -= len) < 0)
return S_FALSE;
ptrdiff_t srcPos = (ptrdiff_t)(Int32)((pos - _win) - (ptrdiff_t)dist - 1);
if (srcPos < 0)
{
if (!_overWin)
return S_FALSE;
UInt32 rem = (UInt32)-srcPos;
srcPos += winSize;
if (rem < len)
{
const Byte *src = _win + srcPos;
len -= rem;
do
*pos++ = *src++;
while (--rem);
srcPos = 0;
}
}
const Byte *src = _win + srcPos;
do
*pos++ = *src++;
while (--len);
// if (outSize == 0) break;
}
}
_winPos = (UInt32)(size_t)(pos - _win);
return rc.Finish() ? S_OK : S_FALSE;
}
HRESULT CDecoder::SetParams(unsigned numDictBits)
{
if (numDictBits > 21)
return E_INVALIDARG;
_numDictBits = numDictBits;
_winPos = 0;
_overWin = false;
if (numDictBits < 15)
numDictBits = 15;
_winSize = (UInt32)1 << numDictBits;
if (!_win || _winSize > _winSize_allocated)
{
MidFree(_win);
_win = NULL;
_win = (Byte *)MidAlloc(_winSize);
if (!_win)
return E_OUTOFMEMORY;
_winSize_allocated = _winSize;
}
return S_OK;
}
}}
@@ -0,0 +1,60 @@
// QuantumDecoder.h
#ifndef ZIP7_INC_COMPRESS_QUANTUM_DECODER_H
#define ZIP7_INC_COMPRESS_QUANTUM_DECODER_H
#include "../../Common/MyTypes.h"
namespace NCompress {
namespace NQuantum {
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 CRangeDecoder;
class CModelDecoder
{
unsigned NumItems;
unsigned ReorderCount;
Byte Vals[kNumSymbolsMax];
UInt16 Freqs[kNumSymbolsMax + 1];
public:
Byte _pad[64 - 10]; // for structure size alignment
void Init(unsigned numItems, unsigned startVal);
unsigned Decode(CRangeDecoder *rc);
};
class CDecoder
{
UInt32 _winSize;
UInt32 _winPos;
UInt32 _winSize_allocated;
bool _overWin;
Byte *_win;
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:
HRESULT Code(const Byte *inData, size_t inSize, UInt32 outSize, bool keepHistory);
HRESULT SetParams(unsigned numDictBits);
CDecoder(): _win(NULL), _numDictBits(0) {}
const Byte * GetDataPtr() const { return _win + _winPos; }
};
}}
#endif
@@ -0,0 +1,518 @@
// 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 (;;)
{
const UInt32 num = numTab[i];
const 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);
}
const 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;
const UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256]
if (flagsPlace >= Z7_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 (unsigned j = 0; j < 32; j++, CharSet++)
*CharSet = (*CharSet & ~(UInt32)0xff) | (unsigned)i;
memset(NumToPlace, 0, sizeof(NToPl));
for (i = 6; i >= 0; i--)
NumToPlace[i] = (7 - (unsigned)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 (unsigned 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();
}
Z7_COM7F_IMF(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; }
}
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
{
if (size < 1)
return E_INVALIDARG;
_isSolid = ((data[0] & 1) != 0);
return S_OK;
}
}}
@@ -0,0 +1,70 @@
// Rar1Decoder.h
// According to unRAR license, this code may not be used to develop
// a program that creates RAR archives
#ifndef ZIP7_INC_COMPRESS_RAR1_DECODER_H
#define ZIP7_INC_COMPRESS_RAR1_DECODER_H
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "../Common/InBuffer.h"
#include "BitmDecoder.h"
#include "LzOutWindow.h"
namespace NCompress {
namespace NRar1 {
const unsigned kNumRepDists = 4;
Z7_CLASS_IMP_COM_2(
CDecoder
, ICompressCoder
, ICompressSetDecoderProperties2
)
bool _isSolid;
bool _solidAllowed;
bool StMode;
CLzOutWindow m_OutWindowStream;
NBitm::CDecoder<CInBuffer> m_InBitStream;
UInt64 m_UnpackSize;
UInt32 LastDist;
UInt32 LastLength;
UInt32 m_RepDistPtr;
UInt32 m_RepDists[kNumRepDists];
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();
};
}}
#endif
@@ -0,0 +1,472 @@
// Rar2Decoder.cpp
// According to unRAR license, this code may not be used to develop
// a program that creates RAR archives
#include "StdAfx.h"
#include <stdlib.h>
#include "Rar2Decoder.h"
namespace NCompress {
namespace NRar2 {
namespace NMultimedia {
#define my_abs(x) (unsigned)abs(x)
Byte CFilter::Decode(int &channelDelta, Byte deltaByte)
{
D4 = D3;
D3 = D2;
D2 = LastDelta - D1;
D1 = LastDelta;
const int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3);
const Byte realValue = (Byte)(predictedValue - deltaByte);
{
const int i = ((int)(signed char)deltaByte) << 3;
Dif[0] += my_abs(i);
Dif[1] += my_abs(i - D1);
Dif[2] += my_abs(i + D1);
Dif[3] += my_abs(i - D2);
Dif[4] += my_abs(i + D2);
Dif[5] += my_abs(i - D3);
Dif[6] += my_abs(i + D3);
Dif[7] += my_abs(i - D4);
Dif[8] += my_abs(i + D4);
Dif[9] += my_abs(i - channelDelta);
Dif[10] += my_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 < Z7_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 < kNumReps; 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; }
static const unsigned kRepBothNumber = 256;
static const unsigned kRepNumber = kRepBothNumber + 1;
static const unsigned kLen2Number = kRepNumber + kNumReps;
static const unsigned kReadTableNumber = kLen2Number + kNumLen2Symbols;
static const unsigned kMatchNumber = kReadTableNumber + 1;
// static const unsigned kDistTableStart = kMainTableSize;
// static const unsigned kLenTableStart = kDistTableStart + kDistTableSize;
static 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};
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};
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 kDistLimit2 = 0x101 - 1;
static const UInt32 kDistLimit3 = 0x2000 - 1;
static const UInt32 kDistLimit4 = 0x40000 - 1;
// static const UInt32 kMatchMaxLen = 255 + 2;
// static const UInt32 kMatchMaxLenMax = 255 + 5;
bool CDecoder::ReadTables(void)
{
m_TablesOK = false;
const unsigned kLevelTableSize = 19;
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 * k_MM_TableSize;
}
else
numLevels = kHeapTablesSizesSum;
unsigned i;
for (i = 0; i < kLevelTableSize; i++)
levelLevels[i] = (Byte)ReadBits(4);
NHuffman::CDecoder256<kNumHufBits, kLevelTableSize, 6> m_LevelDecoder;
RIF(m_LevelDecoder.Build(levelLevels, NHuffman::k_BuildMode_Full))
i = 0;
do
{
const unsigned sym = m_LevelDecoder.DecodeFull(&m_InBitStream);
if (sym < 16)
{
lens[i] = (Byte)((sym + m_LastLevels[i]) & 15);
i++;
}
#if 0
else if (sym >= kLevelTableSize)
return false;
#endif
else
{
unsigned num;
Byte v;
if (sym == 16)
{
if (i == 0)
return false;
num = ReadBits(2) + 3;
v = lens[(size_t)i - 1];
}
else
{
num = (sym - 17) * 4;
num += num + 3 + ReadBits(3 + num);
v = 0;
}
num += i;
if (num > numLevels)
{
// return false;
num = numLevels; // original unRAR
}
do
lens[i++] = v;
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[(size_t)i * k_MM_TableSize]))
}
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)
{
const unsigned symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
if (symbol == 256)
return ReadTables();
if (symbol >= k_MM_TableSize)
return false;
}
else
{
const unsigned 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)
{
const unsigned 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);
*/
const Byte byReal = m_MmFilter.Decode((Byte)symbol);
m_OutWindowStream.PutByte(byReal);
if (++m_MmFilter.CurrentChannel == m_NumChannels)
m_MmFilter.CurrentChannel = 0;
}
return true;
}
typedef unsigned CLenType;
static inline CLenType SlotToLen(CBitDecoder &_bitStream, CLenType slot)
{
const unsigned numBits = ((unsigned)slot >> 2) - 1;
return ((4 | (slot & 3)) << numBits) + (CLenType)_bitStream.ReadBits(numBits);
}
bool CDecoder::DecodeLz(Int32 pos)
{
while (pos > 0)
{
unsigned sym = m_MainDecoder.Decode(&m_InBitStream);
if (m_InBitStream.ExtraBitsWereRead())
return false;
UInt32 len, distance;
if (sym < 256)
{
m_OutWindowStream.PutByte(Byte(sym));
pos--;
continue;
}
else if (sym >= kMatchNumber)
{
if (sym >= kMainTableSize)
return false;
len = sym - kMatchNumber;
if (len >= 8)
len = SlotToLen(m_InBitStream, len);
len += 3;
sym = m_DistDecoder.Decode(&m_InBitStream);
if (sym >= kDistTableSize)
return false;
distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
if (distance >= kDistLimit3)
{
len += 2 - ((distance - kDistLimit4) >> 31);
// len++;
// if (distance >= kDistLimit4)
// len++;
}
}
else if (sym == kRepBothNumber)
{
len = m_LastLength;
if (len == 0)
return false;
distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
}
else if (sym < kLen2Number)
{
distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3];
len = m_LenDecoder.Decode(&m_InBitStream);
if (len >= kLenTableSize)
return false;
if (len >= 8)
len = SlotToLen(m_InBitStream, len);
len += 2;
if (distance >= kDistLimit2)
{
len++;
if (distance >= kDistLimit3)
{
len += 2 - ((distance - kDistLimit4) >> 31);
// len++;
// if (distance >= kDistLimit4)
// len++;
}
}
}
else if (sym < kReadTableNumber)
{
sym -= kLen2Number;
distance = kLen2DistStarts[sym] +
m_InBitStream.ReadBits(kLen2DistDirectBits[sym]);
len = 2;
}
else // (sym == kReadTableNumber)
return true;
m_RepDists[m_RepDistPtr++ & 3] = distance;
m_LastLength = len;
if (!m_OutWindowStream.CopyBlock(distance, len))
return false;
pos -= len;
}
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;
const 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;
const 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();
}
Z7_COM7F_IMF(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; }
}
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
{
if (size < 1)
return E_INVALIDARG;
_isSolid = ((data[0] & 1) != 0);
return S_OK;
}
}}
@@ -0,0 +1,111 @@
// Rar2Decoder.h
// According to unRAR license, this code may not be used to develop
// a program that creates RAR archives
#ifndef ZIP7_INC_COMPRESS_RAR2_DECODER_H
#define ZIP7_INC_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 kNumReps = 4;
const unsigned kDistTableSize = 48;
const unsigned kNumLen2Symbols = 8;
const unsigned kLenTableSize = 28;
const unsigned kMainTableSize = 256 + 2 + kNumReps + kNumLen2Symbols + kLenTableSize;
const unsigned kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize;
const unsigned k_MM_TableSize = 256 + 1;
const unsigned k_MM_NumChanelsMax = 4;
const unsigned k_MM_TablesSizesSum = k_MM_TableSize * k_MM_NumChanelsMax;
const unsigned kMaxTableSize = k_MM_TablesSizesSum;
namespace NMultimedia {
struct CFilter
{
int K1,K2,K3,K4,K5;
int D1,D2,D3,D4;
int LastDelta;
UInt32 Dif[11];
UInt32 ByteCount;
int LastChar;
void Init() { memset(this, 0, sizeof(*this)); }
Byte Decode(int &channelDelta, Byte delta);
};
struct CFilter2
{
CFilter m_Filters[k_MM_NumChanelsMax];
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 kNumHufBits = 15;
Z7_CLASS_IMP_NOQIB_2(
CDecoder
, ICompressCoder
, ICompressSetDecoderProperties2
)
bool _isSolid;
bool _solidAllowed;
bool m_TablesOK;
bool m_AudioMode;
CLzOutWindow m_OutWindowStream;
CBitDecoder m_InBitStream;
UInt32 m_RepDistPtr;
UInt32 m_RepDists[kNumReps];
UInt32 m_LastLength;
unsigned m_NumChannels;
NHuffman::CDecoder<kNumHufBits, kMainTableSize, 9> m_MainDecoder;
NHuffman::CDecoder256<kNumHufBits, kDistTableSize, 7> m_DistDecoder;
NHuffman::CDecoder256<kNumHufBits, kLenTableSize, 7> m_LenDecoder;
NHuffman::CDecoder<kNumHufBits, k_MM_TableSize, 9> m_MMDecoders[k_MM_NumChanelsMax];
UInt64 m_PackSize;
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();
};
}}
#endif
@@ -0,0 +1,939 @@
// 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 unsigned kSymbolReadTable = 256;
static const unsigned kSymbolRep = 259;
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 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" {
static Byte Wrap_ReadByte(IByteInPtr pp) throw()
{
CByteIn *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj);
return p->BitDecoder.Stream.ReadByte();
}
static Byte Wrap_ReadBits8(IByteInPtr pp) throw()
{
CByteIn *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj);
return (Byte)p->BitDecoder.ReadByteFromAligned();
}
}
CDecoder::CDecoder():
_isSolid(false),
_solidAllowed(false),
_window(NULL),
_winPos(0),
_wrPtr(0),
_lzSize(0),
_writtenFileSize(0),
_vmData(NULL),
_vmCode(NULL)
{
Ppmd7_Construct(&_ppmd);
UInt32 start = 0;
for (UInt32 i = 0; i < kDistTableSize; i++)
{
kDistStart[i] = start;
start += ((UInt32)1 << kDistDirectBits[i]);
}
}
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)
{
const unsigned num = _tempFilters.Size();
CTempFilter **tempFilters = _tempFilters.NonConstData();
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 len = (firstByte & 7) + 1;
if (len == 7)
len = ReadBits(8) + 7;
else if (len == 8)
len = ReadBits(16);
if (len > kVmDataSizeMax)
return false;
for (UInt32 i = 0; i < len; i++)
_vmData[i] = (Byte)ReadBits(8);
return AddVmCode(firstByte, len);
}
// int CDecoder::DecodePpmSymbol() { return Ppmd7a_DecodeSymbol(&_ppmd); }
#define DecodePpmSymbol() Ppmd7a_DecodeSymbol(&_ppmd)
bool CDecoder::ReadVmCodePPM()
{
const int firstByte = DecodePpmSymbol();
if (firstByte < 0)
return false;
UInt32 len = (firstByte & 7) + 1;
if (len == 7)
{
const int b1 = DecodePpmSymbol();
if (b1 < 0)
return false;
len = (unsigned)b1 + 7;
}
else if (len == 8)
{
const int b1 = DecodePpmSymbol();
if (b1 < 0)
return false;
const int b2 = DecodePpmSymbol();
if (b2 < 0)
return false;
len = (unsigned)b1 * 256 + (unsigned)b2;
}
if (len > kVmDataSizeMax)
return false;
if (InputEofError_Fast())
return false;
for (UInt32 i = 0; i < len; i++)
{
const int b = DecodePpmSymbol();
if (b < 0)
return false;
_vmData[i] = (Byte)b;
}
return AddVmCode((unsigned)firstByte, len);
}
#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);
const bool reset = ((maxOrder & 0x20) != 0);
UInt32 maxMB = 0;
if (reset)
maxMB = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj);
else
{
if (PpmError || !Ppmd7_WasAllocated(&_ppmd))
return S_FALSE;
}
if (maxOrder & 0x40)
PpmEscChar = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj);
_ppmd.rc.dec.Stream = &m_InBitStream.IByteIn_obj;
m_InBitStream.IByteIn_obj.Read = Wrap_ReadBits8;
Ppmd7a_RangeDec_Init(&_ppmd.rc.dec);
m_InBitStream.IByteIn_obj.Read = Wrap_ReadByte;
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;
}
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;
const int c = DecodePpmSymbol();
if (c < 0)
{
PpmError = true;
return S_FALSE;
}
if (c == PpmEscChar)
{
const 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 dist = 0;
UInt32 len = 4;
if (nextCh == 4)
{
for (int i = 0; i < 3; i++)
{
const int c2 = DecodePpmSymbol();
if (c2 < 0)
{
PpmError = true;
return S_FALSE;
}
dist = (dist << 8) + (Byte)c2;
}
dist++;
len += 28;
}
const int c2 = DecodePpmSymbol();
if (c2 < 0)
{
PpmError = true;
return S_FALSE;
}
len += (unsigned)c2;
if (dist >= _lzSize)
return S_FALSE;
CopyBlock(dist, len);
num -= (Int32)len;
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;
const unsigned kLevelTableSize = 20;
Byte levelLevels[kLevelTableSize];
Byte lens[kTablesSizesSum];
if (ReadBits(1) == 0)
memset(m_LastLevels, 0, kTablesSizesSum);
unsigned i;
for (i = 0; i < kLevelTableSize; i++)
{
const UInt32 len = ReadBits(4);
if (len == 15)
{
UInt32 zeroCount = ReadBits(4);
if (zeroCount != 0)
{
zeroCount += 2;
while (zeroCount-- > 0 && i < kLevelTableSize)
levelLevels[i++]=0;
i--;
continue;
}
}
levelLevels[i] = (Byte)len;
}
NHuffman::CDecoder256<kNumHuffmanBits, kLevelTableSize, 6> m_LevelDecoder;
RIF(m_LevelDecoder.Build(levelLevels, NHuffman::k_BuildMode_Full))
i = 0;
do
{
const unsigned sym = m_LevelDecoder.DecodeFull(&m_InBitStream.BitDecoder);
if (sym < 16)
{
lens[i] = Byte((sym + m_LastLevels[i]) & 15);
i++;
}
#if 0
else if (sym > kLevelTableSize)
return S_FALSE;
#endif
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);
}
HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
{
UInt32 rep0 = _reps[0];
UInt32 rep1 = _reps[1];
UInt32 rep2 = _reps[2];
UInt32 rep3 = _reps[3];
UInt32 len = _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;
unsigned 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 (len == 0)
return S_FALSE;
}
else if (sym < kSymbolRep + 4)
{
if (sym != kSymbolRep)
{
UInt32 dist;
if (sym == kSymbolRep + 1)
dist = rep1;
else
{
if (sym == kSymbolRep + 2)
dist = rep2;
else
{
dist = rep3;
rep3 = rep2;
}
rep2 = rep1;
}
rep1 = rep0;
rep0 = dist;
}
const unsigned sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder);
if (sym2 >= kLenTableSize)
return S_FALSE;
len = 2 + sym2;
if (sym2 >= 8)
{
const unsigned num = (sym2 >> 2) - 1;
len = 2 + (UInt32)((4 + (sym2 & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num);
}
}
else
{
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
if (sym < 271)
{
sym -= 263;
rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits_upto8(kLen2DistDirectBits[sym]);
len = 2;
}
else if (sym < 299)
{
sym -= 271;
len = kNormalMatchMinLen + sym;
if (sym >= 8)
{
const unsigned num = (sym >> 2) - 1;
len = kNormalMatchMinLen + (UInt32)((4 + (sym & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num);
}
const unsigned 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 unsigned 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_upto8(numBits);
len += ((UInt32)(kDistLimit4 - rep0) >> 31) + ((UInt32)(kDistLimit3 - rep0) >> 31);
}
else
return S_FALSE;
}
if (rep0 >= _lzSize)
return S_FALSE;
CopyBlock(rep0, len);
}
_reps[0] = rep0;
_reps[1] = rep1;
_reps[2] = rep2;
_reps[3] = rep3;
_lastLength = len;
return S_OK;
}
HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
{
_writtenFileSize = 0;
_unsupportedFilter = false;
if (!_isSolid)
{
_lzSize = 0;
_winPos = 0;
_wrPtr = 0;
for (unsigned 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;
const UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize();
RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize))
if (!keepDecompressing)
break;
}
_solidAllowed = true;
RINOK(WriteBuf())
const 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;
}
Z7_COM7F_IMF(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.
}
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
{
if (size < 1)
return E_INVALIDARG;
_isSolid = ((data[0] & 1) != 0);
return S_OK;
}
}}
@@ -0,0 +1,283 @@
// 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 ZIP7_INC_COMPRESS_RAR3_DECODER_H
#define ZIP7_INC_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 unsigned kNumHuffmanBits = 15;
const UInt32 kWindowSize = 1 << 22;
const UInt32 kWindowMask = kWindowSize - 1;
const unsigned kNumReps = 4;
const unsigned kNumLen2Symbols = 8;
const unsigned kLenTableSize = 28;
const unsigned kMainTableSize = 256 + 3 + kNumReps + kNumLen2Symbols + kLenTableSize;
const unsigned kDistTableSize = 60;
const unsigned kNumAlignBits = 4;
const unsigned kAlignTableSize = (1 << kNumAlignBits) + 1;
const unsigned 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);
}
Z7_FORCE_INLINE
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);
}
Z7_FORCE_INLINE
UInt32 GetValue_InHigh32bits()
{
return GetValue(kNumHuffmanBits) << (32 - kNumHuffmanBits);
}
Z7_FORCE_INLINE
void MovePos(unsigned numBits)
{
_bitPos -= numBits;
_value = _value & ((1 << _bitPos) - 1);
}
UInt32 ReadBits(unsigned numBits)
{
const UInt32 res = GetValue(numBits);
MovePos(numBits);
return res;
}
UInt32 ReadBits_upto8(unsigned numBits)
{
if (_bitPos < numBits)
{
_bitPos += 8;
_value = (_value << 8) | Stream.ReadByte();
}
_bitPos -= numBits;
const UInt32 res = _value >> _bitPos;
_value = _value & ((1 << _bitPos) - 1);
return res;
}
Byte ReadByteFromAligned()
{
if (_bitPos == 0)
return Stream.ReadByte();
const unsigned bitsPos = _bitPos - 8;
const Byte b = (Byte)(_value >> bitsPos);
_value = _value & ((1 << bitsPos) - 1);
_bitPos = bitsPos;
return b;
}
};
struct CByteIn
{
IByteIn IByteIn_obj;
CBitDecoder BitDecoder;
};
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();
}
};
Z7_CLASS_IMP_NOQIB_2(
CDecoder
, ICompressCoder
, ICompressSetDecoderProperties2
)
bool _isSolid;
bool _solidAllowed;
// bool _errorMode;
bool _lzMode;
bool _unsupportedFilter;
CByteIn 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, 9> m_MainDecoder;
UInt32 kDistStart[kDistTableSize];
NHuffman::CDecoder256<kNumHuffmanBits, kDistTableSize, 7> m_DistDecoder;
NHuffman::CDecoder256<kNumHuffmanBits, kAlignTableSize, 6> m_AlignDecoder;
NHuffman::CDecoder256<kNumHuffmanBits, kLenTableSize, 7> m_LenDecoder;
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;
UInt32 PrevAlignBits;
UInt32 PrevAlignCount;
bool TablesRead;
bool TablesOK;
bool PpmError;
int PpmEscChar;
CPpmd7 _ppmd;
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); }
void CopyBlock(UInt32 dist, UInt32 len)
{
_lzSize += len;
UInt32 pos = (_winPos - dist - 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)
{
const UInt32 wp = _winPos;
_window[wp] = b;
_winPos = (wp + 1) & kWindowMask;
_lzSize++;
}
public:
CDecoder();
~CDecoder();
};
}}
#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 ZIP7_INC_COMPRESS_RAR3_VM_H
#define ZIP7_INC_COMPRESS_RAR3_VM_H
#include "../../../C/CpuArch.h"
#include "../../Common/MyVector.h"
#define Z7_RARVM_STANDARD_FILTERS
// #define Z7_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 Z7_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 Z7_RARVM_VM_ENABLE
void ReadProgram(const Byte *code, UInt32 codeSize);
public:
CRecordVector<CCommand> Commands;
#endif
public:
#ifdef Z7_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 Z7_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 Z7_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
}}}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,132 @@
// Rar5Decoder.h
// According to unRAR license, this code may not be used to develop
// a program that creates RAR archives
#ifndef ZIP7_INC_COMPRESS_RAR5_DECODER_H
#define ZIP7_INC_COMPRESS_RAR5_DECODER_H
#include "../../Common/MyBuffer2.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "HuffmanDecoder.h"
namespace NCompress {
namespace NRar5 {
class CBitDecoder;
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 kExtraDistSymbols_v7 = 16;
const unsigned kDistTableSize_v6 = 64;
const unsigned kDistTableSize_MAX = 64 + kExtraDistSymbols_v7;
const unsigned kNumAlignBits = 4;
const unsigned kAlignTableSize = 1 << kNumAlignBits;
const unsigned kNumHufBits = 15;
const unsigned k_NumHufTableBits_Main = 10;
const unsigned k_NumHufTableBits_Dist = 7;
const unsigned k_NumHufTableBits_Len = 7;
const unsigned k_NumHufTableBits_Align = 6;
const unsigned DICT_SIZE_BITS_MAX = 40;
Z7_CLASS_IMP_NOQIB_2(
CDecoder
, ICompressCoder
, ICompressSetDecoderProperties2
)
bool _useAlignBits;
bool _isLastBlock;
bool _unpackSize_Defined;
// bool _packSize_Defined;
bool _unsupportedFilter;
Byte _lzError;
bool _writeError;
bool _isSolid;
// bool _solidAllowed;
bool _is_v7;
bool _tableWasFilled;
bool _wasInit;
Byte _exitType;
// Byte _dictSizeLog;
size_t _dictSize;
Byte *_window;
size_t _winPos;
size_t _winSize;
size_t _dictSize_forCheck;
size_t _limit;
const Byte *_buf_Res;
UInt64 _lzSize;
size_t _reps[kNumReps];
unsigned _bitPos_Res;
UInt32 _lastLen;
// unsigned _numCorrectDistSymbols;
unsigned _numUnusedFilters;
unsigned _numFilters;
UInt64 _lzWritten;
UInt64 _lzFileStart;
UInt64 _unpackSize;
// UInt64 _packSize;
UInt64 _lzEnd;
UInt64 _writtenFileSize;
UInt64 _filterEnd;
UInt64 _progress_Pack;
UInt64 _progress_Unpack;
CAlignedBuffer _filterSrc;
CAlignedBuffer _filterDst;
CFilter *_filters;
size_t _winSize_Allocated;
ISequentialInStream *_inStream;
ISequentialOutStream *_outStream;
ICompressProgressInfo *_progress;
Byte *_inputBuf;
NHuffman::CDecoder<kNumHufBits, kMainTableSize, k_NumHufTableBits_Main> m_MainDecoder;
NHuffman::CDecoder256<kNumHufBits, kDistTableSize_MAX, k_NumHufTableBits_Dist> m_DistDecoder;
NHuffman::CDecoder256<kNumHufBits, kAlignTableSize, k_NumHufTableBits_Align> m_AlignDecoder;
NHuffman::CDecoder256<kNumHufBits, kLenTableSize, k_NumHufTableBits_Len> m_LenDecoder;
Byte m_LenPlusTable[DICT_SIZE_BITS_MAX];
void InitFilters()
{
_numUnusedFilters = 0;
_numFilters = 0;
}
void DeleteUnusedFilters();
HRESULT WriteData(const Byte *data, size_t size);
HRESULT ExecuteFilter(const CFilter &f);
HRESULT WriteBuf();
HRESULT AddFilter(CBitDecoder &_bitStream);
HRESULT ReadTables(CBitDecoder &_bitStream);
HRESULT DecodeLZ2(const CBitDecoder &_bitStream) throw();
HRESULT DecodeLZ();
HRESULT CodeReal();
public:
CDecoder();
~CDecoder();
};
}}
#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 = (int)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;
}
Z7_COM7F_IMF(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; }
}
Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
{
_fullStreamMode = (finishMode != 0);
return S_OK;
}
Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
{
*value = _inProcessed;
return S_OK;
}
}}
@@ -0,0 +1,35 @@
// ShrinkDecoder.h
#ifndef ZIP7_INC_COMPRESS_SHRINK_DECODER_H
#define ZIP7_INC_COMPRESS_SHRINK_DECODER_H
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
namespace NShrink {
const unsigned kNumMaxBits = 13;
const unsigned kNumItems = 1 << kNumMaxBits;
Z7_CLASS_IMP_NOQIB_3(
CDecoder
, ICompressCoder
, ICompressSetFinishMode
, ICompressGetInStreamProcessedSize
)
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);
};
}}
#endif
+11
View File
@@ -0,0 +1,11 @@
// StdAfx.h
#ifndef ZIP7_INC_STDAFX_H
#define ZIP7_INC_STDAFX_H
#if defined(_MSC_VER) && _MSC_VER >= 1800
#pragma warning(disable : 4464) // relative include path contains '..'
#endif
#include "../../Common/Common.h"
#endif
@@ -0,0 +1,399 @@
// XpressDecoder.cpp
#include "StdAfx.h"
#include "../../../C/CpuArch.h"
#include "../../../C/RotateDefs.h"
#include "HuffmanDecoder.h"
#include "XpressDecoder.h"
#ifdef MY_CPU_LE_UNALIGN
#define Z7_XPRESS_DEC_USE_UNALIGNED_COPY
#endif
#ifdef Z7_XPRESS_DEC_USE_UNALIGNED_COPY
#define COPY_CHUNK_SIZE 16
#define COPY_CHUNK_4_2(dest, src) \
{ \
((UInt32 *)(void *)dest)[0] = ((const UInt32 *)(const void *)src)[0]; \
((UInt32 *)(void *)dest)[1] = ((const UInt32 *)(const void *)src)[1]; \
src += 4 * 2; \
dest += 4 * 2; \
}
/* sse2 doesn't help here in GCC and CLANG.
so we disabled sse2 here */
#if 0
#if defined(MY_CPU_AMD64)
#define Z7_XPRESS_DEC_USE_SSE2
#elif defined(MY_CPU_X86)
#if defined(_MSC_VER) && _MSC_VER >= 1300 && defined(_M_IX86_FP) && (_M_IX86_FP >= 2) \
|| defined(__SSE2__) \
// || 1 == 1 // for debug only
#define Z7_XPRESS_DEC_USE_SSE2
#endif
#endif
#endif
#if defined(MY_CPU_ARM64)
#include <arm_neon.h>
#define COPY_OFFSET_MIN 16
#define COPY_CHUNK1(dest, src) \
{ \
vst1q_u8((uint8_t *)(void *)dest, \
vld1q_u8((const uint8_t *)(const void *)src)); \
src += 16; \
dest += 16; \
}
#define COPY_CHUNK(dest, src) \
{ \
COPY_CHUNK1(dest, src) \
if (dest >= dest_lim) break; \
COPY_CHUNK1(dest, src) \
}
#elif defined(Z7_XPRESS_DEC_USE_SSE2)
#include <emmintrin.h> // sse2
#define COPY_OFFSET_MIN 16
#define COPY_CHUNK1(dest, src) \
{ \
_mm_storeu_si128((__m128i *)(void *)dest, \
_mm_loadu_si128((const __m128i *)(const void *)src)); \
src += 16; \
dest += 16; \
}
#define COPY_CHUNK(dest, src) \
{ \
COPY_CHUNK1(dest, src) \
if (dest >= dest_lim) break; \
COPY_CHUNK1(dest, src) \
}
#elif defined(MY_CPU_64BIT)
#define COPY_OFFSET_MIN 8
#define COPY_CHUNK(dest, src) \
{ \
((UInt64 *)(void *)dest)[0] = ((const UInt64 *)(const void *)src)[0]; \
((UInt64 *)(void *)dest)[1] = ((const UInt64 *)(const void *)src)[1]; \
src += 8 * 2; \
dest += 8 * 2; \
}
#else
#define COPY_OFFSET_MIN 4
#define COPY_CHUNK(dest, src) \
{ \
COPY_CHUNK_4_2(dest, src); \
COPY_CHUNK_4_2(dest, src); \
}
#endif
#endif
#ifndef COPY_CHUNK_SIZE
#define COPY_OFFSET_MIN 4
#define COPY_CHUNK_SIZE 8
#define COPY_CHUNK_2(dest, src) \
{ \
const Byte a0 = src[0]; \
const Byte a1 = src[1]; \
dest[0] = a0; \
dest[1] = a1; \
src += 2; \
dest += 2; \
}
#define COPY_CHUNK(dest, src) \
{ \
COPY_CHUNK_2(dest, src) \
COPY_CHUNK_2(dest, src) \
COPY_CHUNK_2(dest, src) \
COPY_CHUNK_2(dest, src) \
}
#endif
#define COPY_CHUNKS \
{ \
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \
do { COPY_CHUNK(dest, src) } \
while (dest < dest_lim); \
}
static
Z7_FORCE_INLINE
// Z7_ATTRIB_NO_VECTOR
void CopyMatch_1(Byte *dest, const Byte *dest_lim)
{
const unsigned b0 = dest[-1];
{
#if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY) && (COPY_CHUNK_SIZE == 16)
#if defined(MY_CPU_64BIT)
{
const UInt64 v64 = (UInt64)b0 * 0x0101010101010101;
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
do
{
((UInt64 *)(void *)dest)[0] = v64;
((UInt64 *)(void *)dest)[1] = v64;
dest += 16;
}
while (dest < dest_lim);
}
#else
{
UInt32 v = b0;
v |= v << 8;
v |= v << 16;
do
{
((UInt32 *)(void *)dest)[0] = v;
((UInt32 *)(void *)dest)[1] = v;
dest += 8;
((UInt32 *)(void *)dest)[0] = v;
((UInt32 *)(void *)dest)[1] = v;
dest += 8;
}
while (dest < dest_lim);
}
#endif
#else
do
{
dest[0] = (Byte)b0;
dest[1] = (Byte)b0;
dest += 2;
dest[0] = (Byte)b0;
dest[1] = (Byte)b0;
dest += 2;
}
while (dest < dest_lim);
#endif
}
}
// (offset != 1)
static
Z7_FORCE_INLINE
// Z7_ATTRIB_NO_VECTOR
void CopyMatch_Non1(Byte *dest, size_t offset, const Byte *dest_lim)
{
const Byte *src = dest - offset;
{
// (COPY_OFFSET_MIN >= 4)
if (offset >= COPY_OFFSET_MIN)
{
COPY_CHUNKS
// return;
}
else
#if (COPY_OFFSET_MIN > 4)
#if COPY_CHUNK_SIZE < 8
#error Stop_Compiling_Bad_COPY_CHUNK_SIZE
#endif
if (offset >= 4)
{
Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
do
{
COPY_CHUNK_4_2(dest, src)
#if COPY_CHUNK_SIZE != 16
if (dest >= dest_lim) break;
#endif
COPY_CHUNK_4_2(dest, src)
}
while (dest < dest_lim);
// return;
}
else
#endif
{
// (offset < 4)
if (offset == 2)
{
#if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY)
UInt32 w0 = GetUi16(src);
w0 += w0 << 16;
do
{
SetUi32(dest, w0)
dest += 4;
}
while (dest < dest_lim);
#else
const unsigned b0 = src[0];
const Byte b1 = src[1];
do
{
dest[0] = (Byte)b0;
dest[1] = b1;
dest += 2;
}
while (dest < dest_lim);
#endif
}
else // (offset == 3)
{
const unsigned b0 = src[0];
#if defined(Z7_XPRESS_DEC_USE_UNALIGNED_COPY)
const unsigned w1 = GetUi16(src + 1);
do
{
dest[0] = (Byte)b0;
SetUi16(dest + 1, (UInt16)w1)
dest += 3;
}
while (dest < dest_lim);
#else
const Byte b1 = src[1];
const Byte b2 = src[2];
do
{
dest[0] = (Byte)b0;
dest[1] = b1;
dest[2] = b2;
dest += 3;
}
while (dest < dest_lim);
#endif
}
}
}
}
namespace NCompress {
namespace NXpress {
#define BIT_STREAM_NORMALIZE \
if (BitPos > 16) { \
if (in >= lim) return S_FALSE; \
BitPos -= 16; \
Value |= (UInt32)GetUi16(in) << BitPos; \
in += 2; }
#define MOVE_POS(bs, numBits) \
BitPos += (unsigned)numBits; \
Value <<= numBits; \
static const unsigned kNumHuffBits = 15;
static const unsigned kNumTableBits = 10;
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_WithExceedWrite(const Byte *in, size_t inSize, Byte *out, size_t outSize)
{
NCompress::NHuffman::CDecoder<kNumHuffBits, kNumSyms, kNumTableBits> huff;
if (inSize < kNumSyms / 2 + 4)
return S_FALSE;
{
Byte levels[kNumSyms];
for (unsigned i = 0; i < kNumSyms / 2; i++)
{
const unsigned b = in[i];
levels[(size_t)i * 2 ] = (Byte)(b & 0xf);
levels[(size_t)i * 2 + 1] = (Byte)(b >> 4);
}
if (!huff.Build(levels, NHuffman::k_BuildMode_Full))
return S_FALSE;
}
UInt32 Value;
unsigned BitPos; // how many bits in (Value) were processed
const Byte *lim = in + inSize - 1; // points to last byte
in += kNumSyms / 2;
#ifdef MY_CPU_LE_UNALIGN
Value = GetUi32(in);
Value = rotlFixed(Value, 16);
#else
Value = ((UInt32)GetUi16(in) << 16) | GetUi16(in + 2);
#endif
in += 4;
BitPos = 0;
Byte *dest = out;
const Byte *outLim = out + outSize;
for (;;)
{
unsigned sym;
Z7_HUFF_DECODE_VAL_IN_HIGH32(sym, &huff, kNumHuffBits, kNumTableBits,
Value, Z7_HUFF_DECODE_ERROR_SYM_CHECK_NO, {}, MOVE_POS, {}, bs)
// 0 < BitPos <= 31
BIT_STREAM_NORMALIZE
// 0 < BitPos <= 16
if (dest >= outLim)
return (sym == 256 && Value == 0 && in == lim + 1) ? S_OK : S_FALSE;
if (sym < 256)
*dest++ = (Byte)sym;
else
{
const unsigned distBits = (unsigned)(Byte)sym >> kNumLenBits; // (sym - 256) >> kNumLenBits;
UInt32 len = (UInt32)(sym & kLenMask);
if (len == kLenMask)
{
if (in > lim)
return S_FALSE;
// here we read input bytes in out-of-order related to main input stream (bits in Value):
len = *in++;
if (len == 0xff)
{
if (in >= lim)
return S_FALSE;
len = GetUi16(in);
in += 2;
}
else
len += kLenMask;
}
len += 3;
if (len > (size_t)(outLim - dest))
return S_FALSE;
if (distBits == 0)
{
// d == 1
if (dest == out)
return S_FALSE;
Byte *destTemp = dest;
dest += len;
CopyMatch_1(destTemp, dest);
}
else
{
unsigned d = (unsigned)(Value >> (32 - distBits));
MOVE_POS(bs, distBits)
d += 1u << distBits;
// 0 < BitPos <= 31
BIT_STREAM_NORMALIZE
// 0 < BitPos <= 16
if (d > (size_t)(dest - out))
return S_FALSE;
Byte *destTemp = dest;
dest += len;
CopyMatch_Non1(destTemp, d, dest);
}
}
}
}
}}
@@ -0,0 +1,18 @@
// XpressDecoder.h
#ifndef ZIP7_INC_XPRESS_DECODER_H
#define ZIP7_INC_XPRESS_DECODER_H
#include "../../Common/MyTypes.h"
namespace NCompress {
namespace NXpress {
// (out) buffer size must be larger than (outSize) for the following value:
const unsigned kAdditionalOutputBufSize = 32;
HRESULT Decode_WithExceedWrite(const Byte *in, size_t inSize, Byte *out, size_t outSize);
}}
#endif
@@ -0,0 +1,151 @@
// 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;
default: break;
}
return S_FALSE;
}
HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *progress)
{
MainDecodeSRes = SZ_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 Z7_ST
{
props.numThreads = 1;
const 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 Z7_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; // for debug check
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);
}
Z7_COM7F_IMF(CComDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
{
return Decode(inStream, outStream, outSize, _finishStream, progress);
}
Z7_COM7F_IMF(CComDecoder::SetFinishMode(UInt32 finishMode))
{
_finishStream = (finishMode != 0);
return S_OK;
}
Z7_COM7F_IMF(CComDecoder::GetInStreamProcessedSize(UInt64 *value))
{
*value = Stat.InSize;
return S_OK;
}
#ifndef Z7_ST
Z7_COM7F_IMF(CComDecoder::SetNumberOfThreads(UInt32 numThreads))
{
_numThreads = numThreads;
return S_OK;
}
Z7_COM7F_IMF(CComDecoder::SetMemLimit(UInt64 memUsage))
{
_memUsage = memUsage;
return S_OK;
}
#endif
}}
@@ -0,0 +1,86 @@
// XzDecoder.h
#ifndef ZIP7_INC_XZ_DECODER_H
#define ZIP7_INC_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 S_OK, if there is data after good xz streams, and that data is not new xz stream.
check also (Stat.DataAfterEnd) flag */
HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *compressProgress);
};
class CComDecoder Z7_final:
public ICompressCoder,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
#ifndef Z7_ST
public ICompressSetCoderMt,
public ICompressSetMemLimit,
#endif
public CMyUnknownImp,
public CDecoder
{
Z7_COM_QI_BEGIN2(ICompressCoder)
Z7_COM_QI_ENTRY(ICompressSetFinishMode)
Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
#ifndef Z7_ST
Z7_COM_QI_ENTRY(ICompressSetCoderMt)
Z7_COM_QI_ENTRY(ICompressSetMemLimit)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(ICompressCoder)
Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
#ifndef Z7_ST
Z7_IFACE_COM7_IMP(ICompressSetCoderMt)
Z7_IFACE_COM7_IMP(ICompressSetMemLimit)
#endif
bool _finishStream;
public:
CComDecoder(): _finishStream(false) {}
};
}}
#endif
@@ -0,0 +1,243 @@
// 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 < Z7_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)
{
const 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
{
const int filterId = FilterIdFromName(prop.bstrVal);
if (filterId < 0 /* || filterId == XZ_ID_LZMA2 */)
return E_INVALIDARG;
id32 = (UInt32)(unsigned)filterId;
}
}
if (id32 == XZ_ID_Delta)
{
const wchar_t c = *name;
if (c != '-' && c != ':')
return E_INVALIDARG;
name++;
const 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);
}
Z7_COM7F_IMF(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));
}
Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
const PROPVARIANT *coderProps, UInt32 numProps))
{
for (UInt32 i = 0; i < numProps; i++)
{
const PROPVARIANT &prop = coderProps[i];
const 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;
Z7_COM7F_IMF(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,35 @@
// XzEncoder.h
#ifndef ZIP7_INC_XZ_ENCODER_H
#define ZIP7_INC_XZ_ENCODER_H
#include "../../../C/XzEnc.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
namespace NXz {
Z7_CLASS_IMP_COM_3(
CEncoder
, ICompressCoder
, ICompressSetCoderProperties
, ICompressSetCoderPropertiesOpt
)
CXzEncHandle _encoder;
public:
CXzProps xzProps;
void InitCoderProps();
HRESULT SetCheckSize(UInt32 checkSizeInBytes);
HRESULT SetCoderProp(PROPID propID, const PROPVARIANT &prop);
CEncoder();
~CEncoder();
};
}}
#endif
@@ -0,0 +1,235 @@
// 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 size_t 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 = NULL;
MyFree(_suffixes); _suffixes = NULL;
MyFree(_stack); _stack = NULL;
}
CDecoder::~CDecoder() { Free(); }
HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
ICompressProgressInfo *progress)
{
try {
// PackSize = 0;
CInBuffer inBuffer;
COutBuffer outBuffer;
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;
}
const Byte prop = buf[2];
if ((prop & 0x60) != 0)
return S_FALSE;
const unsigned maxbits = prop & kNumBitsMask;
if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
return S_FALSE;
const UInt32 numItems = (UInt32)1 << maxbits;
// Speed optimization: blockSymbol can contain unused velue.
if (maxbits != _numMaxBits || !_parents || !_suffixes || !_stack)
{
Free();
_parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (!_parents) return E_OUTOFMEMORY;
_suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_suffixes) return E_OUTOFMEMORY;
_stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_stack) return E_OUTOFMEMORY;
_numMaxBits = maxbits;
}
UInt64 prevPos = 0;
const 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;
const UInt64 nowPos = outBuffer.GetProcessedSize();
if (progress && nowPos - prevPos >= (1 << 13))
{
prevPos = nowPos;
const UInt64 packSize = inBuffer.GetProcessedSize();
RINOK(progress->SetRatioInfo(&packSize, &nowPos))
}
}
const 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 &= ((UInt32)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();
const HRESULT res2 = outBuffer.Flush();
return (res == S_OK) ? res2 : res;
}
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;
const Byte prop = data[2];
if ((prop & 0x60) != 0)
return false;
const unsigned maxbits = prop & kNumBitsMask;
if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
return false;
const UInt32 numItems = (UInt32)1 << maxbits;
const 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)
{
const unsigned num = (numBits < size) ? numBits : (unsigned)size;
memcpy(buf, data, num);
data += num;
size -= num;
numBufBits = num * 8;
bitPos = 0;
}
const unsigned bytePos = bitPos >> 3;
UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16);
symbol >>= (bitPos & 7);
symbol &= ((UInt32)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,47 @@
// ZDecoder.h
#ifndef ZIP7_INC_COMPRESS_Z_DECODER_H
#define ZIP7_INC_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
{
UInt16 *_parents;
Byte *_suffixes;
Byte *_stack;
unsigned _numMaxBits;
public:
CDecoder(): _parents(NULL), _suffixes(NULL), _stack(NULL), /* _prop(0), */ _numMaxBits(0) {}
~CDecoder();
void Free();
// UInt64 PackSize;
HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
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,136 @@
// ZlibDecoder.cpp
#include "StdAfx.h"
#include "../../../C/CpuArch.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 *data, size_t size);
UInt32 Adler32_Update(UInt32 adler, const Byte *data, size_t size)
{
if (size == 0)
return adler;
UInt32 a = adler & 0xffff;
UInt32 b = adler >> 16;
do
{
size_t cur = size;
if (cur > ADLER_LOOP_MAX)
cur = ADLER_LOOP_MAX;
size -= cur;
const Byte *lim = data + cur;
if (cur >= 4)
{
lim -= 4 - 1;
do
{
a += data[0]; b += a;
a += data[1]; b += a;
a += data[2]; b += a;
a += data[3]; b += a;
data += 4;
}
while (data < lim);
lim += 4 - 1;
}
if (data != lim) { a += *data++; b += a;
if (data != lim) { a += *data++; b += a;
if (data != lim) { a += *data++; b += a; }}}
a %= ADLER_MOD;
b %= ADLER_MOD;
}
while (size);
return (b << 16) + a;
}
Z7_COM7F_IMF(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;
}
Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
{
DEFLATE_TRY_BEGIN
_inputProcessedSize_Additional = 0;
AdlerStream.Create_if_Empty();
DeflateDecoder.Create_if_Empty();
DeflateDecoder->Set_NeedFinishInput(true);
if (inSize && *inSize < 2)
return S_FALSE;
{
Byte buf[2];
RINOK(ReadStream_FALSE(inStream, buf, 2))
if (!IsZlib(buf))
return S_FALSE;
}
_inputProcessedSize_Additional = 2;
AdlerStream->SetStream(outStream);
AdlerStream->Init();
// NDeflate::NDecoder::Code() ignores inSize
/*
UInt64 inSize2 = 0;
if (inSize)
inSize2 = *inSize - 2;
*/
const HRESULT res = DeflateDecoder.Interface()->Code(inStream, AdlerStream,
/* inSize ? &inSize2 : */ NULL, outSize, progress);
AdlerStream->ReleaseStream();
if (res == S_OK)
{
UInt32 footer32[1];
UInt32 processedSize;
RINOK(DeflateDecoder->ReadUnusedFromInBuf(footer32, 4, &processedSize))
if (processedSize != 4)
{
size_t processedSize2 = 4 - processedSize;
RINOK(ReadStream(inStream, (Byte *)(void *)footer32 + processedSize, &processedSize2))
_inputProcessedSize_Additional += (Int32)processedSize2;
processedSize += (UInt32)processedSize2;
}
if (processedSize == 4)
{
const UInt32 adler = GetBe32a(footer32);
if (adler != AdlerStream->GetAdler())
return S_FALSE; // adler error
}
else if (!IsAdlerOptional)
return S_FALSE; // unexpeced end of stream (can't read adler)
else
{
// IsAdlerOptional == true
if (processedSize != 0)
{
// we exclude adler bytes from processed size:
_inputProcessedSize_Additional -= (Int32)processedSize;
return S_FALSE;
}
}
}
return res;
DEFLATE_TRY_END
}
}}
@@ -0,0 +1,78 @@
// ZlibDecoder.h
#ifndef ZIP7_INC_ZLIB_DECODER_H
#define ZIP7_INC_ZLIB_DECODER_H
#include "DeflateDecoder.h"
namespace NCompress {
namespace NZlib {
const UInt32 ADLER_INIT_VAL = 1;
Z7_CLASS_IMP_NOQIB_1(
COutStreamWithAdler
, ISequentialOutStream
)
UInt32 _adler;
CMyComPtr<ISequentialOutStream> _stream;
UInt64 _size;
public:
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; }
};
Z7_CLASS_IMP_NOQIB_1(
CDecoder
, ICompressCoder
)
CMyComPtr2<ISequentialOutStream, COutStreamWithAdler> AdlerStream;
CMyComPtr2<ICompressCoder, NDeflate::NDecoder::CCOMCoder> DeflateDecoder;
Int32 _inputProcessedSize_Additional;
public:
bool IsAdlerOptional;
CDecoder(): IsAdlerOptional(false) {}
UInt64 GetInputProcessedSize() const
{
return (UInt64)(
(Int64)DeflateDecoder->GetInputProcessedSize() +
(Int64)_inputProcessedSize_Additional);
}
UInt64 GetOutputProcessedSize() const { return AdlerStream->GetSize(); }
};
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;
const unsigned val = p[2];
const 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);
Z7_COM7F_IMF(CInStreamWithAdler::Read(void *data, UInt32 size, UInt32 *processedSize))
{
const HRESULT result = _stream->Read(data, size, &size);
_adler = Adler32_Update(_adler, (const Byte *)data, size);
_size += size;
if (processedSize)
*processedSize = size;
return result;
}
void CEncoder::Create()
{
if (!DeflateEncoder)
DeflateEncoder = DeflateEncoderSpec = new NDeflate::NEncoder::CCOMCoder;
}
Z7_COM7F_IMF(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();
const HRESULT res = DeflateEncoder->Code(AdlerStream, outStream, inSize, NULL, progress);
AdlerSpec->ReleaseStream();
RINOK(res)
{
const UInt32 a = AdlerSpec->GetAdler();
const 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,42 @@
// ZlibEncoder.h
#ifndef ZIP7_INC_ZLIB_ENCODER_H
#define ZIP7_INC_ZLIB_ENCODER_H
#include "DeflateEncoder.h"
namespace NCompress {
namespace NZlib {
Z7_CLASS_IMP_NOQIB_1(
CInStreamWithAdler
, ISequentialInStream
)
CMyComPtr<ISequentialInStream> _stream;
UInt32 _adler;
UInt64 _size;
public:
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; }
};
Z7_CLASS_IMP_NOQIB_1(
CEncoder
, ICompressCoder
)
CInStreamWithAdler *AdlerSpec;
CMyComPtr<ISequentialInStream> AdlerStream;
CMyComPtr<ICompressCoder> DeflateEncoder;
public:
NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec;
void Create();
UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); }
};
}}
#endif

Some files were not shown because too many files have changed in this diff Show More