chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0 Architectures: x86-ansi, x86-unicode, amd64-unicode License: LGPL-2.1-or-later
This commit is contained in:
@@ -0,0 +1,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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user