This commit is contained in:
Igor Pavlov
2017-04-30 00:00:00 +00:00
committed by Kornel
parent 603abd5528
commit 2efa10565a
442 changed files with 15479 additions and 8525 deletions

View File

@@ -13,8 +13,8 @@ void CBZip2Crc::InitTable()
for (UInt32 i = 0; i < 256; i++)
{
UInt32 r = (i << 24);
for (int j = 8; j > 0; j--)
r = (r & 0x80000000) ? ((r << 1) ^ kBZip2CrcPoly) : (r << 1);
for (unsigned j = 0; j < 8; j++)
r = (r << 1) ^ (kBZip2CrcPoly & ((UInt32)0 - (r >> 31)));
Table[i] = r;
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,9 @@
#include "../../Common/MyCom.h"
// #define NO_READ_FROM_CODER
// #define _7ZIP_ST
#ifndef _7ZIP_ST
#include "../../Windows/Synchronization.h"
#include "../../Windows/Thread.h"
@@ -12,13 +15,10 @@
#include "../ICoder.h"
#include "../Common/InBuffer.h"
#include "../Common/OutBuffer.h"
#include "BitmDecoder.h"
#include "BZip2Const.h"
#include "BZip2Crc.h"
#include "HuffmanDecoder.h"
#include "Mtf8.h"
namespace NCompress {
namespace NBZip2 {
@@ -26,154 +26,311 @@ namespace NBZip2 {
bool IsEndSig(const Byte *p) throw();
bool IsBlockSig(const Byte *p) throw();
typedef NCompress::NHuffman::CDecoder<kMaxHuffmanLen, kMaxAlphaSize> CHuffmanDecoder;
const unsigned kNumTableBits = 9;
const unsigned kNumBitsMax = kMaxHuffmanLen;
class CDecoder;
typedef NHuffman::CDecoder<kMaxHuffmanLen, kMaxAlphaSize, kNumTableBits> CHuffmanDecoder;
struct CState
{
UInt32 *Counters;
#ifndef _7ZIP_ST
CDecoder *Decoder;
NWindows::CThread Thread;
bool m_OptimizeNumTables;
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;
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
HRESULT Create();
void FinishStream();
void ThreadFunc();
#endif
CState(): Counters(0) {}
~CState() { Free(); }
bool Alloc();
void Free();
};
struct CBlockProps
{
UInt32 blockSize;
UInt32 origPtr;
bool randMode;
unsigned randMode;
CBlockProps(): blockSize(0), origPtr(0), randMode(false) {}
CBlockProps(): blockSize(0), origPtr(0), randMode(0) {}
};
struct CBase
struct CBitDecoder
{
CMyComPtr<ISequentialInStream> InStreamRef;
NBitm::CDecoder<CInBuffer> BitDecoder;
unsigned _numBits;
UInt32 _value;
const Byte *_buf;
const Byte *_lim;
private:
Byte m_Selectors[kNumSelectorsMax];
CHuffmanDecoder m_HuffmanDecoders[kNumTablesMax];
void InitBitDecoder()
{
_numBits = 0;
_value = 0;
}
public:
UInt64 NumBlocks;
CBase(): NumBlocks(0) {}
UInt32 ReadBits(unsigned numBits);
unsigned ReadBit();
void InitNumBlocks() { NumBlocks = 0; }
void AlignToByte()
{
unsigned bits = _numBits & 7;
_numBits -= bits;
_value <<= bits;
}
/*
ReadBlock() props->randMode:
in: need read randMode bit,
out: randMode status
bool AreRemainByteBitsEmpty() const
{
unsigned bits = _numBits & 7;
if (bits != 0)
return (_value >> (32 - bits)) == 0;
return true;
}
*/
HRESULT ReadBlock(UInt32 *charCounters, UInt32 blockSizeMax, CBlockProps *props);
SRes ReadByte(int &b);
};
struct CBase: public CBitDecoder
{
unsigned numInUse;
UInt32 groupIndex;
UInt32 groupSize;
unsigned runPower;
UInt32 runCounter;
UInt32 blockSize;
UInt32 *Counters;
UInt32 blockSizeMax;
unsigned state;
unsigned state2;
unsigned state3;
unsigned state4;
unsigned state5;
unsigned numTables;
UInt32 numSelectors;
CBlockProps Props;
private:
CMtf8Decoder mtf;
Byte selectors[kNumSelectorsMax];
CHuffmanDecoder huffs[kNumTablesMax];
Byte lens[kMaxAlphaSize];
Byte temp[10];
public:
UInt32 crc;
CBZip2CombinedCrc CombinedCrc;
bool IsBz;
bool StreamCrcError;
bool MinorError;
bool NeedMoreInput;
bool DecodeAllStreams;
UInt64 NumStreams;
UInt64 NumBlocks;
UInt64 FinishedPackSize;
ISequentialInStream *InStream;
#ifndef NO_READ_FROM_CODER
CMyComPtr<ISequentialInStream> InStreamRef;
#endif
CBase():
StreamCrcError(false),
MinorError(false),
NeedMoreInput(false),
DecodeAllStreams(false),
NumStreams(0),
NumBlocks(0),
FinishedPackSize(0)
{}
void InitNumStreams2()
{
StreamCrcError = false;
MinorError = false;
NeedMoreInput = 0;
NumStreams = 0;
NumBlocks = 0;
FinishedPackSize = 0;
}
SRes ReadStreamSignature2();
SRes ReadBlockSignature2();
/* ReadBlock2() : Props->randMode:
in: need read randMode bit
out: randMode status */
SRes ReadBlock2();
};
class CSpecState
{
UInt32 _tPos;
unsigned _prevByte;
int _reps;
public:
CBZip2Crc _crc;
UInt32 _blockSize;
UInt32 *_tt;
int _randToGo;
unsigned _randIndex;
void Init(UInt32 origPtr, unsigned randMode) throw();
bool Finished() const { return _reps <= 0 && _blockSize == 0; }
Byte *Decode(Byte *data, size_t size) throw();
};
class CDecoder :
public ICompressCoder,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
#ifndef NO_READ_FROM_CODER
public ICompressSetInStream,
public ICompressSetOutStreamSize,
public ISequentialInStream,
#endif
#ifndef _7ZIP_ST
public ICompressSetCoderMt,
#endif
public CMyUnknownImp
{
Byte *_outBuf;
size_t _outPos;
UInt64 _outWritten;
ISequentialOutStream *_outStream;
HRESULT _writeRes;
protected:
HRESULT ErrorResult; // for ISequentialInStream::Read mode only
public:
COutBuffer m_OutStream;
Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
CBase Base;
UInt32 _calcedBlockCrc;
bool _blockFinished;
bool BlockCrcError;
UInt64 _inStart;
bool FinishMode;
bool _outSizeDefined;
UInt64 _outSize;
UInt64 _outPosTotal;
private:
CSpecState _spec;
UInt32 *_counters;
bool _needInStreamInit;
#ifndef _7ZIP_ST
Byte ReadByte();
struct CBlock
{
bool StopScout;
bool WasFinished;
bool Crc_Defined;
// bool NextCrc_Defined;
UInt32 Crc;
UInt32 NextCrc;
HRESULT Res;
UInt64 PackPos;
CBlockProps Props;
};
HRESULT DecodeFile(ICompressProgressInfo *progress);
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
CBlock _block;
bool NeedWaitScout;
bool MtMode;
NWindows::CThread Thread;
NWindows::NSynchronization::CAutoResetEvent DecoderEvent;
NWindows::NSynchronization::CAutoResetEvent ScoutEvent;
// HRESULT ScoutRes;
class CDecoderFlusher
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:
bool NeedFlush;
CDecoderFlusher(CDecoder *decoder): _decoder(decoder), NeedFlush(true) {}
~CDecoderFlusher()
{
if (NeedFlush)
_decoder->Flush();
}
CWaitScout_Releaser(CDecoder *decoder): _decoder(decoder) {}
~CWaitScout_Releaser() { _decoder->WaitScout(); }
};
public:
CBZip2CombinedCrc CombinedCrc;
ICompressProgressInfo *Progress;
HRESULT CreateThread();
#ifndef _7ZIP_ST
CState *m_States;
UInt32 m_NumThreadsPrev;
NWindows::NSynchronization::CManualResetEvent CanProcessEvent;
NWindows::NSynchronization::CCriticalSection CS;
UInt32 NumThreads;
bool MtMode;
UInt32 NextBlockIndex;
bool CloseThreads;
bool StreamWasFinished1;
bool StreamWasFinished2;
NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
HRESULT Result1;
HRESULT Result2;
UInt32 BlockSizeMax;
~CDecoder();
HRESULT Create();
void Free();
#else
CState m_States[1];
#endif
bool IsBz;
bool BzWasFinished; // bzip stream was finished with end signature
bool CrcError; // it can CRC error of block or CRC error of whole stream.
Byte *_inBuf;
UInt64 _inProcessed;
bool _inputFinished;
HRESULT _inputRes;
CDecoder();
CBase Base;
HRESULT SetRatioProgress(UInt64 packSize);
HRESULT ReadSignature(UInt32 &crc);
bool GetCrcError() const { return BlockCrcError || Base.StreamCrcError; }
HRESULT Flush() { return m_OutStream.Flush(); }
void InitOutSize(const UInt64 *outSize);
bool CreateInputBufer();
void InitInputBuffer()
{
_inProcessed = 0;
Base._buf = _inBuf;
Base._lim = _inBuf;
Base.InitBitDecoder();
}
UInt64 GetInputProcessedSize() const
{
// for NSIS case : we need also look the number of bits in bitDecoder
return _inProcessed + (Base._buf - _inBuf);
}
UInt64 GetOutProcessedSize() const { return _outWritten + _outPos; }
HRESULT ReadInput();
void StartNewStream();
HRESULT ReadStreamSignature();
HRESULT StartRead();
HRESULT ReadBlockSignature();
HRESULT ReadBlock();
HRESULT Flush();
HRESULT DecodeBlock(const CBlockProps &props);
HRESULT DecodeStreams(ICompressProgressInfo *progress);
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
#ifndef NO_READ_FROM_CODER
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
#endif
#ifndef _7ZIP_ST
MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
#endif
@@ -185,54 +342,41 @@ public:
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
STDMETHOD(ReleaseInStream)();
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
HRESULT CodeResume(ISequentialOutStream *outStream, ICompressProgressInfo *progress);
UInt64 GetStreamSize() const { return Base.BitDecoder.GetStreamSize(); }
UInt64 GetInputProcessedSize() const { return Base.BitDecoder.GetProcessedSize(); }
void InitNumBlocks() { Base.InitNumBlocks(); }
UInt64 GetNumStreams() const { return Base.NumStreams; }
UInt64 GetNumBlocks() const { return Base.NumBlocks; }
#ifndef _7ZIP_ST
STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
#endif
};
#ifndef NO_READ_FROM_CODER
class CNsisDecoder :
public ISequentialInStream,
public ICompressSetInStream,
public ICompressSetOutStreamSize,
public CMyUnknownImp
{
CBase Base;
CState m_State;
int _nsisState;
UInt32 _tPos;
unsigned _prevByte;
unsigned _repRem;
unsigned _numReps;
UInt32 _blockSize;
public:
MY_QUERYINTERFACE_BEGIN2(ISequentialInStream)
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
STDMETHOD(ReleaseInStream)();
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
#endif
#ifndef _7ZIP_ST
STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
#endif
CDecoder();
~CDecoder();
};
#ifndef NO_READ_FROM_CODER
class CNsisDecoder : public CDecoder
{
public:
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
};
#endif
}}
#endif

View File

@@ -337,7 +337,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
}
else
mtfs[mtfArraySize++] = (Byte)(pos + 1);
symbolCounts[pos + 1]++;
symbolCounts[(size_t)pos + 1]++;
}
}
while (++i < blockSize);
@@ -357,7 +357,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
mtfs[mtfArraySize++] = 0xFF;
mtfs[mtfArraySize++] = (Byte)(alphaSize - 256);
}
symbolCounts[alphaSize - 1]++;
symbolCounts[(size_t)alphaSize - 1]++;
}
UInt32 numSymbols = 0;
@@ -412,7 +412,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
if (ge > gs + 1 && t != numTables && t != 1 && (((numTables - t) & 1) == 1))
aFreq -= symbolCounts[--ge];
Byte *lens = Lens[t - 1];
Byte *lens = Lens[(size_t)t - 1];
unsigned i = 0;
do
lens[i] = (Byte)((i >= gs && i < ge) ? 0 : 1);
@@ -507,7 +507,7 @@ void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
WriteBit2(1);
WriteBit2(0);
for (; pos > 0; pos--)
mtfSel[pos] = mtfSel[pos - 1];
mtfSel[pos] = mtfSel[(size_t)pos - 1];
mtfSel[0] = sel;
}
while (++i < numSelectors);
@@ -634,10 +634,13 @@ void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPa
UInt32 endPos = 0;
if (numPasses > 1 && blockSize >= (1 << 10))
{
UInt32 blockSize0 = blockSize / 2;
for (;(block[blockSize0] == block[blockSize0 - 1] ||
block[blockSize0 - 1] == block[blockSize0 - 2]) &&
blockSize0 < blockSize; blockSize0++);
UInt32 blockSize0 = blockSize / 2; // ????
for (; (block[blockSize0] == block[(size_t)blockSize0 - 1]
|| block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2])
&& blockSize0 < blockSize;
blockSize0++);
if (blockSize0 < blockSize)
{
EncodeBlock2(block, blockSize0, numPasses - 1);

View File

@@ -463,10 +463,10 @@ HRESULT CDecoder::Code(ISequentialInStream * const *inStreams, const UInt64 * co
if (progress)
{
UInt64 outSize2 = outSizeProcessed + (dec.dest - _bufs[BCJ2_NUM_STREAMS]);
const UInt64 outSize2 = outSizeProcessed + (dec.dest - _bufs[BCJ2_NUM_STREAMS]);
if (outSize2 - prevProgress >= (1 << 22))
{
UInt64 inSize2 = outSize2 + _inStreamsProcessed[BCJ2_STREAM_RC] - (dec.lims[BCJ2_STREAM_RC] - dec.bufs[BCJ2_STREAM_RC]);
const UInt64 inSize2 = outSize2 + _inStreamsProcessed[BCJ2_STREAM_RC] - (dec.lims[BCJ2_STREAM_RC] - dec.bufs[BCJ2_STREAM_RC]);
RINOK(progress->SetRatioInfo(&inSize2, &outSize2));
prevProgress = outSize2;
}
@@ -655,4 +655,12 @@ STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
return res;
}
STDMETHODIMP CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)
{
const size_t rem = dec.lims[streamIndex] - dec.bufs[streamIndex] + _extraReadSizes[streamIndex];
*value = _inStreamsProcessed[streamIndex] - rem;
return S_OK;
}
}}

View File

@@ -62,6 +62,7 @@ public:
class CDecoder:
public ICompressCoder2,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize2,
public ICompressSetInStream2,
public ISequentialInStream,
public ICompressSetOutStreamSize,
@@ -84,9 +85,10 @@ class CDecoder:
// HRESULT ReadSpec();
public:
MY_UNKNOWN_IMP6(
MY_UNKNOWN_IMP7(
ICompressCoder2,
ICompressSetFinishMode,
ICompressGetInStreamProcessedSize2,
ICompressSetInStream2,
ISequentialInStream,
ICompressSetOutStreamSize,
@@ -98,6 +100,7 @@ public:
ICompressProgressInfo *progress);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize2)(UInt32 streamIndex, UInt64 *value);
STDMETHOD(SetInStream2)(UInt32 streamIndex, ISequentialInStream *inStream);
STDMETHOD(ReleaseInStream2)(UInt32 streamIndex);

View File

@@ -42,13 +42,15 @@ public:
UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); }
bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; }
MY_FORCE_INLINE
void Normalize()
{
for (; _bitPos >= 8; _bitPos -= 8)
_value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value;
}
MY_FORCE_INLINE
UInt32 ReadBits(unsigned numBits)
{
Normalize();
@@ -88,7 +90,8 @@ public:
CBaseDecoder<TInByte>::Init();
_normalValue = 0;
}
MY_FORCE_INLINE
void Normalize()
{
for (; this->_bitPos >= 8; this->_bitPos -= 8)
@@ -99,18 +102,21 @@ public:
}
}
MY_FORCE_INLINE
UInt32 GetValue(unsigned numBits)
{
Normalize();
return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits);
}
MY_FORCE_INLINE
void MovePos(unsigned numBits)
{
this->_bitPos += numBits;
_normalValue >>= numBits;
}
MY_FORCE_INLINE
UInt32 ReadBits(unsigned numBits)
{
Normalize();
@@ -120,9 +126,11 @@ public:
}
void AlignToByte() { MovePos((32 - this->_bitPos) & 7); }
MY_FORCE_INLINE
Byte ReadDirectByte() { return this->_stream.ReadByte(); }
MY_FORCE_INLINE
Byte ReadAlignedByte()
{
if (this->_bitPos == kNumBigValueBits)

View File

@@ -46,25 +46,29 @@ public:
{
return (_stream.NumExtraBytes > 4);
}
MY_FORCE_INLINE
void Normalize()
{
for (; _bitPos >= 8; _bitPos -= 8)
_value = (_value << 8) | _stream.ReadByte();
}
MY_FORCE_INLINE
UInt32 GetValue(unsigned numBits) const
{
// return (_value << _bitPos) >> (kNumBigValueBits - numBits);
return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits);
}
MY_FORCE_INLINE
void MovePos(unsigned numBits)
{
_bitPos += numBits;
Normalize();
}
MY_FORCE_INLINE
UInt32 ReadBits(unsigned numBits)
{
UInt32 res = GetValue(numBits);
@@ -87,6 +91,7 @@ public:
void AlignToByte() { MovePos((kNumBigValueBits - _bitPos) & 7); }
MY_FORCE_INLINE
UInt32 ReadAlignBits() { return ReadBits((kNumBigValueBits - _bitPos) & 7); }
};

View File

@@ -15,6 +15,11 @@ CCopyCoder::~CCopyCoder()
::MidFree(_buf);
}
STDMETHODIMP CCopyCoder::SetFinishMode(UInt32 /* finishMode */)
{
return S_OK;
}
STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream,
ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize,

View File

@@ -13,6 +13,7 @@ class CCopyCoder:
public ICompressCoder,
public ICompressSetInStream,
public ISequentialInStream,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public CMyUnknownImp
{
@@ -24,10 +25,11 @@ public:
CCopyCoder(): _buf(0), TotalSize(0) {};
~CCopyCoder();
MY_UNKNOWN_IMP4(
MY_UNKNOWN_IMP5(
ICompressCoder,
ICompressSetInStream,
ISequentialInStream,
ICompressSetFinishMode,
ICompressGetInStreamProcessedSize)
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
@@ -35,6 +37,7 @@ public:
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
STDMETHOD(ReleaseInStream)();
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
};

View File

@@ -14,6 +14,8 @@ CCoder::CCoder(bool deflate64Mode):
_keepHistory(false),
_needFinishInput(false),
_needInitInStream(true),
_outSizeDefined(false),
_outStartPos(0),
ZlibMode(false) {}
UInt32 CCoder::ReadBits(unsigned numBits)
@@ -50,7 +52,7 @@ bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols)
return false;
numBits = 2;
num = 0;
symbol = levels[i - 1];
symbol = levels[(size_t)i - 1];
}
else
{
@@ -145,10 +147,28 @@ bool CCoder::ReadTables(void)
return m_DistDecoder.Build(levels.distLevels);
}
HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
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)
@@ -156,6 +176,7 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
return E_OUTOFMEMORY;
RINOK(InitInStream(_needInitInStream));
m_OutWindowStream.Init(_keepHistory);
m_FinalBlock = false;
_remainLen = 0;
_needReadTable = true;
@@ -169,6 +190,10 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
curSize--;
}
UInt64 inputStart = 0;
if (inputProgressLimit != 0)
inputStart = m_InBitStream.GetProcessedSize();
while (curSize > 0 || finishInputStream)
{
if (m_InBitStream.ExtraBitsWereRead())
@@ -181,6 +206,11 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
_remainLen = kLenIdFinished;
break;
}
if (inputProgressLimit != 0)
if (m_InBitStream.GetProcessedSize() - inputStart >= inputProgressLimit)
return S_OK;
if (!ReadTables())
return S_FALSE;
if (m_InBitStream.ExtraBitsWereRead())
@@ -284,31 +314,34 @@ HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream)
#define DEFLATE_TRY_BEGIN try {
#define DEFLATE_TRY_END(res) } \
catch(const CInBufferException &e) { res = e.ErrorCode; } \
catch(const CLzOutWindowException &e) { res = e.ErrorCode; } \
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,
const UInt64 *outSize, ICompressProgressInfo *progress)
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();
const UInt64 start = m_OutWindowStream.GetProcessedSize();
for (;;)
{
UInt32 curSize = 1 << 18;
const UInt32 kInputProgressLimit = 1 << 21;
UInt32 curSize = 1 << 20;
bool finishInputStream = false;
if (outSize)
if (_outSizeDefined)
{
const UInt64 rem = *outSize - (m_OutWindowStream.GetProcessedSize() - start);
const UInt64 rem = _outSize - GetOutProcessedCur();
if (curSize >= rem)
{
curSize = (UInt32)rem;
@@ -318,13 +351,16 @@ HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
}
if (!finishInputStream && curSize == 0)
break;
RINOK(CodeSpec(curSize, finishInputStream));
RINOK(CodeSpec(curSize, finishInputStream, progress ? kInputProgressLimit : 0));
if (_remainLen == kLenIdFinished)
break;
if (progress)
{
const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;
const UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
const UInt64 nowPos64 = GetOutProcessedCur();
RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
}
}
@@ -340,20 +376,36 @@ HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,
res = Flush();
if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError())
return S_FALSE;
DEFLATE_TRY_END(res)
return res;
}
HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
{
SetInStream(inStream);
SetOutStreamSize(outSize);
HRESULT res = CodeReal(outStream, outSize, progress);
HRESULT res = CodeReal(outStream, progress);
ReleaseInStream();
/*
if (res == S_OK)
if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize())
res = S_FALSE;
*/
return res;
}
STDMETHODIMP CCoder::SetFinishMode(UInt32 finishMode)
{
Set_NeedFinishInput(finishMode != 0);
return S_OK;
}
STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
{
if (!value)
@@ -362,6 +414,7 @@ STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
return S_OK;
}
STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream)
{
m_InStreamRef = inStream;
@@ -369,49 +422,88 @@ STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream)
return S_OK;
}
STDMETHODIMP CCoder::ReleaseInStream()
{
m_InStreamRef.Release();
return S_OK;
}
STDMETHODIMP CCoder::SetOutStreamSize(const UInt64 * /* outSize */)
void CCoder::SetOutStreamSizeResume(const UInt64 *outSize)
{
_remainLen = kLenIdNeedInit;
_needInitInStream = true;
_outSizeDefined = (outSize != NULL);
_outSize = 0;
if (_outSizeDefined)
_outSize = *outSize;
m_OutWindowStream.Init(_keepHistory);
_outStartPos = m_OutWindowStream.GetProcessedSize();
_remainLen = kLenIdNeedInit;
}
STDMETHODIMP CCoder::SetOutStreamSize(const UInt64 *outSize)
{
_needInitInStream = true;
SetOutStreamSizeResume(outSize);
return S_OK;
}
#ifndef NO_READ_FROM_CODER
STDMETHODIMP CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
{
HRESULT res;
DEFLATE_TRY_BEGIN
if (processedSize)
*processedSize = 0;
const UInt64 startPos = m_OutWindowStream.GetProcessedSize();
m_OutWindowStream.SetMemStream((Byte *)data);
res = CodeSpec(size, false);
if (res == S_OK)
const UInt64 outPos = GetOutProcessedCur();
bool finishInputStream = false;
if (_outSizeDefined)
{
res = Flush();
if (processedSize)
*processedSize = (UInt32)(m_OutWindowStream.GetProcessedSize() - startPos);
const UInt64 rem = _outSize - outPos;
if (size >= rem)
{
size = (UInt32)rem;
if (ZlibMode || _needFinishInput)
finishInputStream = true;
}
}
if (!finishInputStream && size == 0)
return S_OK;
DEFLATE_TRY_BEGIN
m_OutWindowStream.SetMemStream((Byte *)data);
res = CodeSpec(size, finishInputStream);
DEFLATE_TRY_END(res)
{
HRESULT res2 = Flush();
if (res2 != S_OK)
res = res2;
}
if (processedSize)
*processedSize = (UInt32)(GetOutProcessedCur() - outPos);
m_OutWindowStream.SetMemStream(NULL);
return res;
}
#endif
STDMETHODIMP CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
HRESULT CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
{
_remainLen = kLenIdNeedInit;
m_OutWindowStream.Init(_keepHistory);
return CodeReal(outStream, outSize, progress);
SetOutStreamSizeResume(outSize);
return CodeReal(outStream, progress);
}
}}}

View File

@@ -23,6 +23,7 @@ const int kLenIdNeedInit = -2;
class CCoder:
public ICompressCoder,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
#ifndef NO_READ_FROM_CODER
public ICompressSetInStream,
@@ -54,6 +55,13 @@ class CCoder:
Int32 _remainLen;
UInt32 _rep0;
bool _outSizeDefined;
UInt64 _outSize;
UInt64 _outStartPos;
void SetOutStreamSizeResume(const UInt64 *outSize);
UInt64 GetOutProcessedCur() const { return m_OutWindowStream.GetProcessedSize() - _outStartPos; }
UInt32 ReadBits(unsigned numBits);
bool DecodeLevels(Byte *levels, unsigned numSymbols);
@@ -74,7 +82,7 @@ class CCoder:
};
friend class CCoderReleaser;
HRESULT CodeSpec(UInt32 curSize, bool finishInputStream);
HRESULT CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit = 0);
public:
bool ZlibMode;
Byte ZlibFooter[4];
@@ -90,26 +98,28 @@ public:
bool IsFinished() const { return _remainLen == kLenIdFinished;; }
bool IsFinalBlock() const { return m_FinalBlock; }
HRESULT CodeReal(ISequentialOutStream *outStream,
const UInt64 *outSize, ICompressProgressInfo *progress);
HRESULT CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress);
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
#ifndef NO_READ_FROM_CODER
MY_UNKNOWN_IMP5(
ICompressCoder,
ICompressGetInStreamProcessedSize,
ICompressSetInStream,
ICompressSetOutStreamSize,
ISequentialInStream
)
#else
MY_UNKNOWN_IMP2(
ICompressCoder,
ICompressGetInStreamProcessedSize)
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
#endif
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
STDMETHOD(ReleaseInStream)();
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
@@ -118,19 +128,9 @@ public:
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
#endif
STDMETHOD(CodeResume)(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
HRESULT InitInStream(bool needInit)
{
if (!m_InBitStream.Create(1 << 17))
return E_OUTOFMEMORY;
if (needInit)
{
m_InBitStream.Init();
_needInitInStream = false;
}
return S_OK;
}
HRESULT InitInStream(bool needInit);
void AlignToByte() { m_InBitStream.AlignToByte(); }
Byte ReadAlignedByte();
@@ -143,9 +143,6 @@ public:
UInt64 GetStreamSize() const { return m_InBitStream.GetStreamSize(); }
UInt64 GetInputProcessedSize() const { return m_InBitStream.GetProcessedSize(); }
// IGetInStreamProcessedSize
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
};
class CCOMCoder : public CCoder { public: CCOMCoder(): CCoder(false) {} };

View File

@@ -7,6 +7,8 @@
#include "../../Common/ComTry.h"
#include "../Common/CWrappers.h"
#include "DeflateEncoder.h"
#undef NO_INLINE
@@ -262,19 +264,19 @@ NO_INLINE void CCoder::GetMatches()
UInt32 i;
for (i = 0; i < numPairs; i += 2)
{
m_MatchDistances[i + 1] = (UInt16)distanceTmp[i];
m_MatchDistances[i + 2] = (UInt16)distanceTmp[i + 1];
m_MatchDistances[(size_t)i + 1] = (UInt16)distanceTmp[i];
m_MatchDistances[(size_t)i + 2] = (UInt16)distanceTmp[(size_t)i + 1];
}
UInt32 len = distanceTmp[numPairs - 2];
UInt32 len = distanceTmp[(size_t)numPairs - 2];
if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen)
{
UInt32 numAvail = Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) + 1;
const Byte *pby = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - 1;
const Byte *pby2 = pby - (distanceTmp[numPairs - 1] + 1);
const Byte *pby2 = pby - (distanceTmp[(size_t)numPairs - 1] + 1);
if (numAvail > m_MatchMaxLen)
numAvail = m_MatchMaxLen;
for (; len < numAvail && pby[len] == pby2[len]; len++);
m_MatchDistances[i - 1] = (UInt16)len;
m_MatchDistances[(size_t)i - 1] = (UInt16)len;
}
}
if (m_IsMultiPass)
@@ -337,11 +339,11 @@ NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes)
if (numDistancePairs == 0)
return 1;
const UInt16 *matchDistances = m_MatchDistances + 1;
lenEnd = matchDistances[numDistancePairs - 2];
lenEnd = matchDistances[(size_t)numDistancePairs - 2];
if (lenEnd > m_NumFastBytes)
{
backRes = matchDistances[numDistancePairs - 1];
backRes = matchDistances[(size_t)numDistancePairs - 1];
MovePos(lenEnd - 1);
return lenEnd;
}
@@ -356,10 +358,10 @@ NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes)
for (UInt32 i = kMatchMinLen; i <= lenEnd; i++)
{
UInt32 distance = matchDistances[offs + 1];
UInt32 distance = matchDistances[(size_t)offs + 1];
m_Optimum[i].PosPrev = 0;
m_Optimum[i].BackPrev = (UInt16)distance;
m_Optimum[i].Price = m_LenPrices[i - kMatchMinLen] + m_PosPrices[GetPosSlot(distance)];
m_Optimum[i].Price = m_LenPrices[(size_t)i - kMatchMinLen] + m_PosPrices[GetPosSlot(distance)];
if (i == matchDistances[offs])
offs += 2;
}
@@ -378,11 +380,11 @@ NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes)
UInt32 newLen = 0;
if (numDistancePairs != 0)
{
newLen = matchDistances[numDistancePairs - 2];
newLen = matchDistances[(size_t)numDistancePairs - 2];
if (newLen > m_NumFastBytes)
{
UInt32 len = Backward(backRes, cur);
m_Optimum[cur].BackPrev = matchDistances[numDistancePairs - 1];
m_Optimum[cur].BackPrev = matchDistances[(size_t)numDistancePairs - 1];
m_OptimumEndIndex = cur + newLen;
m_Optimum[cur].PosPrev = (UInt16)m_OptimumEndIndex;
MovePos(newLen - 1);
@@ -392,7 +394,7 @@ NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes)
UInt32 curPrice = m_Optimum[cur].Price;
{
const UInt32 curAnd1Price = curPrice + m_LiteralPrices[*(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) + cur - m_AdditionalOffset)];
COptimal &optimum = m_Optimum[cur + 1];
COptimal &optimum = m_Optimum[(size_t)cur + 1];
if (curAnd1Price < optimum.Price)
{
optimum.Price = curAnd1Price;
@@ -404,11 +406,11 @@ NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes)
while (lenEnd < cur + newLen)
m_Optimum[++lenEnd].Price = kIfinityPrice;
UInt32 offs = 0;
UInt32 distance = matchDistances[offs + 1];
UInt32 distance = matchDistances[(size_t)offs + 1];
curPrice += m_PosPrices[GetPosSlot(distance)];
for (UInt32 lenTest = kMatchMinLen; ; lenTest++)
{
UInt32 curAndLenPrice = curPrice + m_LenPrices[lenTest - kMatchMinLen];
UInt32 curAndLenPrice = curPrice + m_LenPrices[(size_t)lenTest - kMatchMinLen];
COptimal &optimum = m_Optimum[cur + lenTest];
if (curAndLenPrice < optimum.Price)
{
@@ -422,7 +424,7 @@ NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes)
if (offs == numDistancePairs)
break;
curPrice -= m_PosPrices[GetPosSlot(distance)];
distance = matchDistances[offs + 1];
distance = matchDistances[(size_t)offs + 1];
curPrice += m_PosPrices[GetPosSlot(distance)];
}
}
@@ -435,7 +437,7 @@ UInt32 CCoder::GetOptimalFast(UInt32 &backRes)
UInt32 numDistancePairs = m_MatchDistances[0];
if (numDistancePairs == 0)
return 1;
UInt32 lenMain = m_MatchDistances[numDistancePairs - 1];
UInt32 lenMain = m_MatchDistances[(size_t)numDistancePairs - 1];
backRes = m_MatchDistances[numDistancePairs];
MovePos(lenMain - 1);
return lenMain;
@@ -470,7 +472,7 @@ NO_INLINE void CCoder::LevelTableDummy(const Byte *levels, unsigned numLevels, U
for (unsigned n = 0; n < numLevels; n++)
{
unsigned curLen = nextLen;
nextLen = (n < numLevels - 1) ? levels[n + 1] : 0xFF;
nextLen = (n < numLevels - 1) ? levels[(size_t)n + 1] : 0xFF;
count++;
if (count < maxCount && curLen == nextLen)
continue;
@@ -537,7 +539,7 @@ NO_INLINE void CCoder::LevelTableCode(const Byte *levels, unsigned numLevels, co
for (unsigned n = 0; n < numLevels; n++)
{
unsigned curLen = nextLen;
nextLen = (n < numLevels - 1) ? levels[n + 1] : 0xFF;
nextLen = (n < numLevels - 1) ? levels[(size_t)n + 1] : 0xFF;
count++;
if (count < maxCount && curLen == nextLen)
continue;
@@ -642,7 +644,7 @@ NO_INLINE void CCoder::TryBlock()
{
UInt32 newLen = len - kMatchMinLen;
codeValue.Len = (UInt16)newLen;
mainFreqs[kSymbolMatch + g_LenSlots[newLen]]++;
mainFreqs[kSymbolMatch + (size_t)g_LenSlots[newLen]]++;
codeValue.Pos = (UInt16)pos;
distFreqs[GetPosSlot(pos)]++;
}
@@ -675,7 +677,7 @@ NO_INLINE void CCoder::SetPrices(const CLevels &levels)
for (i = 0; i < m_NumLenCombinations; i++)
{
UInt32 slot = g_LenSlots[i];
Byte price = levels.litLenLevels[kSymbolMatch + slot];
Byte price = levels.litLenLevels[kSymbolMatch + (size_t)slot];
m_LenPrices[i] = (Byte)(((price != 0) ? price : kNoLenStatPrice) + m_LenDirectBits[slot]);
}
@@ -780,11 +782,11 @@ NO_INLINE UInt32 CCoder::TryDynBlock(unsigned tableIndex, UInt32 numPasses)
(CLevels &)t = m_NewLevels;
m_NumLitLenLevels = kMainTableSize;
while (m_NumLitLenLevels > kNumLitLenCodesMin && m_NewLevels.litLenLevels[m_NumLitLenLevels - 1] == 0)
while (m_NumLitLenLevels > kNumLitLenCodesMin && m_NewLevels.litLenLevels[(size_t)m_NumLitLenLevels - 1] == 0)
m_NumLitLenLevels--;
m_NumDistLevels = kDistTableSize64;
while (m_NumDistLevels > kNumDistCodesMin && m_NewLevels.distLevels[m_NumDistLevels - 1] == 0)
while (m_NumDistLevels > kNumDistCodesMin && m_NewLevels.distLevels[(size_t)m_NumDistLevels - 1] == 0)
m_NumDistLevels--;
UInt32 levelFreqs[kLevelTableSize];
@@ -923,14 +925,6 @@ void CCoder::CodeBlock(unsigned tableIndex, bool finalBlock)
}
}
SRes Read(void *object, void *data, size_t *size)
{
const UInt32 kStepSize = (UInt32)1 << 31;
UInt32 curSize = ((*size < kStepSize) ? (UInt32)*size : kStepSize);
HRESULT res = ((CSeqInStream *)object)->RealStream->Read(data, curSize, &curSize);
*size = curSize;
return (SRes)res;
}
HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */ , const UInt64 * /* outSize */ , ICompressProgressInfo *progress)
@@ -944,9 +938,11 @@ HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *ou
UInt64 nowPos = 0;
_seqInStream.RealStream = inStream;
_seqInStream.SeqInStream.Read = Read;
_lzInWindow.stream = &_seqInStream.SeqInStream;
CSeqInStreamWrap _seqInStream;
_seqInStream.Init(inStream);
_lzInWindow.stream = &_seqInStream.vt;
MatchFinder_Init(&_lzInWindow);
m_OutStream.SetStream(outStream);
@@ -974,7 +970,7 @@ HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *ou
}
while (Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) != 0);
if (_lzInWindow.result != SZ_OK)
return _lzInWindow.result;
return SResToHRESULT(_lzInWindow.result);
return m_OutStream.Flush();
}

View File

@@ -46,11 +46,6 @@ struct CTables: public CLevels
void InitStructures();
};
typedef struct _CSeqInStream
{
ISeqInStream SeqInStream;
ISequentialInStream *RealStream;
} CSeqInStream;
struct CEncProps
{
@@ -76,8 +71,6 @@ class CCoder
CMatchFinder _lzInWindow;
CBitlEncoder m_OutStream;
CSeqInStream _seqInStream;
public:
CCodeValue *m_Values;

View File

@@ -8,45 +8,52 @@
namespace NCompress {
namespace NHuffman {
const unsigned kNumPairLenBits = 4;
const unsigned kPairLenMask = (1 << kNumPairLenBits) - 1;
template <unsigned kNumBitsMax, UInt32 m_NumSymbols, unsigned kNumTableBits = 9>
class CDecoder
{
public:
UInt32 _limits[kNumBitsMax + 2];
UInt32 _poses[kNumBitsMax + 1];
UInt16 _lens[1 << kNumTableBits];
UInt16 _symbols[m_NumSymbols];
public:
bool Build(const Byte *lens) throw()
{
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
UInt32 counts[kNumBitsMax + 1];
unsigned i;
for (i = 0; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
counts[i] = 0;
UInt32 sym;
for (sym = 0; sym < m_NumSymbols; sym++)
lenCounts[lens[sym]]++;
counts[lens[sym]]++;
lenCounts[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
_limits[0] = 0;
UInt32 startPos = 0;
UInt32 sum = 0;
for (i = 1; i <= kNumBitsMax; i++)
{
startPos += lenCounts[i] << (kNumBitsMax - i);
const UInt32 cnt = counts[i];
startPos += cnt << (kNumBitsMax - i);
if (startPos > kMaxValue)
return false;
_limits[i] = startPos;
_poses[i] = _poses[i - 1] + lenCounts[i - 1];
tmpPoses[i] = _poses[i];
counts[i] = sum;
_poses[i] = sum;
sum += cnt;
}
counts[0] = sum;
_poses[0] = sum;
_limits[kNumBitsMax + 1] = kMaxValue;
for (sym = 0; sym < m_NumSymbols; sym++)
@@ -55,16 +62,15 @@ public:
if (len == 0)
continue;
unsigned offset = tmpPoses[len];
unsigned offset = counts[len]++;
_symbols[offset] = (UInt16)sym;
tmpPoses[len] = offset + 1;
if (len <= kNumTableBits)
{
offset -= _poses[len];
UInt32 num = (UInt32)1 << (kNumTableBits - len);
UInt16 val = (UInt16)((sym << 4) | len);
UInt16 *dest = _lens + (_limits[len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
UInt16 val = (UInt16)((sym << kNumPairLenBits) | len);
UInt16 *dest = _lens + (_limits[(size_t)len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
for (UInt32 k = 0; k < num; k++)
dest[k] = val;
}
@@ -73,36 +79,41 @@ public:
return true;
}
bool BuildFull(const Byte *lens, UInt32 numSymbols = m_NumSymbols) throw()
{
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
UInt32 counts[kNumBitsMax + 1];
unsigned i;
for (i = 0; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
counts[i] = 0;
UInt32 sym;
for (sym = 0; sym < numSymbols; sym++)
lenCounts[lens[sym]]++;
counts[lens[sym]]++;
lenCounts[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
_limits[0] = 0;
UInt32 startPos = 0;
UInt32 sum = 0;
for (i = 1; i <= kNumBitsMax; i++)
{
startPos += lenCounts[i] << (kNumBitsMax - i);
const UInt32 cnt = counts[i];
startPos += cnt << (kNumBitsMax - i);
if (startPos > kMaxValue)
return false;
_limits[i] = startPos;
_poses[i] = _poses[i - 1] + lenCounts[i - 1];
tmpPoses[i] = _poses[i];
counts[i] = sum;
_poses[i] = sum;
sum += cnt;
}
counts[0] = sum;
_poses[0] = sum;
_limits[kNumBitsMax + 1] = kMaxValue;
for (sym = 0; sym < numSymbols; sym++)
@@ -111,16 +122,15 @@ public:
if (len == 0)
continue;
unsigned offset = tmpPoses[len];
unsigned offset = counts[len]++;
_symbols[offset] = (UInt16)sym;
tmpPoses[len] = offset + 1;
if (len <= kNumTableBits)
{
offset -= _poses[len];
UInt32 num = (UInt32)1 << (kNumTableBits - len);
UInt16 val = (UInt16)((sym << 4) | len);
UInt16 *dest = _lens + (_limits[len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
UInt16 val = (UInt16)((sym << kNumPairLenBits) | len);
UInt16 *dest = _lens + (_limits[(size_t)len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
for (UInt32 k = 0; k < num; k++)
dest[k] = val;
}
@@ -129,16 +139,18 @@ public:
return startPos == kMaxValue;
}
template <class TBitDecoder>
UInt32 Decode(TBitDecoder *bitStream) const throw()
MY_FORCE_INLINE
UInt32 Decode(TBitDecoder *bitStream) const
{
UInt32 val = bitStream->GetValue(kNumBitsMax);
if (val < _limits[kNumTableBits])
{
UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
bitStream->MovePos((unsigned)(pair & 0xF));
return pair >> 4;
bitStream->MovePos((unsigned)(pair & kPairLenMask));
return pair >> kNumPairLenBits;
}
unsigned numBits;
@@ -148,27 +160,29 @@ public:
return 0xFFFFFFFF;
bitStream->MovePos(numBits);
UInt32 index = _poses[numBits] + ((val - _limits[numBits - 1]) >> (kNumBitsMax - numBits));
UInt32 index = _poses[numBits] + ((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits));
return _symbols[index];
}
template <class TBitDecoder>
UInt32 DecodeFull(TBitDecoder *bitStream) const throw()
MY_FORCE_INLINE
UInt32 DecodeFull(TBitDecoder *bitStream) const
{
UInt32 val = bitStream->GetValue(kNumBitsMax);
if (val < _limits[kNumTableBits])
{
UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
bitStream->MovePos((unsigned)(pair & 0xF));
return pair >> 4;
bitStream->MovePos((unsigned)(pair & kPairLenMask));
return pair >> kNumPairLenBits;
}
unsigned numBits;
for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
bitStream->MovePos(numBits);
UInt32 index = _poses[numBits] + ((val - _limits[numBits - 1]) >> (kNumBitsMax - numBits));
UInt32 index = _poses[numBits] + ((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits));
return _symbols[index];
}
};
@@ -185,50 +199,54 @@ public:
{
const unsigned kNumBitsMax = 7;
UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPoses[kNumBitsMax + 1];
UInt32 counts[kNumBitsMax + 1];
UInt32 _poses[kNumBitsMax + 1];
UInt32 _limits[kNumBitsMax + 1];
unsigned i;
for (i = 0; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
counts[i] = 0;
UInt32 sym;
for (sym = 0; sym < m_NumSymbols; sym++)
lenCounts[lens[sym]]++;
counts[lens[sym]]++;
lenCounts[0] = 0;
_poses[0] = 0;
_limits[0] = 0;
UInt32 startPos = 0;
const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
_limits[0] = 0;
UInt32 startPos = 0;
UInt32 sum = 0;
for (i = 1; i <= kNumBitsMax; i++)
{
startPos += lenCounts[i] << (kNumBitsMax - i);
const UInt32 cnt = counts[i];
startPos += cnt << (kNumBitsMax - i);
if (startPos > kMaxValue)
return false;
_limits[i] = startPos;
_poses[i] = _poses[i - 1] + lenCounts[i - 1];
tmpPoses[i] = _poses[i];
counts[i] = sum;
_poses[i] = sum;
sum += cnt;
}
counts[0] = sum;
_poses[0] = sum;
for (sym = 0; sym < m_NumSymbols; sym++)
{
unsigned len = lens[sym];
if (len == 0)
continue;
unsigned offset = tmpPoses[len];
tmpPoses[len] = offset + 1;
unsigned offset = counts[len]++;
{
offset -= _poses[len];
UInt32 num = (UInt32)1 << (kNumBitsMax - len);
Byte val = (Byte)((sym << 3) | len);
Byte *dest = _lens + (_limits[len - 1]) + (offset << (kNumBitsMax - len));
Byte *dest = _lens + (_limits[(size_t)len - 1]) + (offset << (kNumBitsMax - len));
for (UInt32 k = 0; k < num; k++)
dest[k] = val;
}
@@ -246,7 +264,7 @@ public:
}
template <class TBitDecoder>
UInt32 Decode(TBitDecoder *bitStream) const throw()
UInt32 Decode(TBitDecoder *bitStream) const
{
UInt32 val = bitStream->GetValue(7);
UInt32 pair = _lens[val];

View File

@@ -10,214 +10,248 @@ namespace NCompress {
namespace NImplode {
namespace NDecoder {
class CException
bool CHuffmanDecoder::Build(const Byte *lens, unsigned numSymbols) throw()
{
public:
enum ECauseType
unsigned counts[kNumHuffmanBits + 1];
unsigned i;
for (i = 0; i <= kNumHuffmanBits; i++)
counts[i] = 0;
unsigned sym;
for (sym = 0; sym < numSymbols; sym++)
counts[lens[sym]]++;
const UInt32 kMaxValue = (UInt32)1 << kNumHuffmanBits;
// _limits[0] = kMaxValue;
UInt32 startPos = kMaxValue;
UInt32 sum = 0;
for (i = 1; i <= kNumHuffmanBits; i++)
{
kData
} m_Cause;
CException(ECauseType cause): m_Cause(cause) {}
};
const UInt32 cnt = counts[i];
const UInt32 range = cnt << (kNumHuffmanBits - i);
if (startPos < range)
return false;
startPos -= range;
_limits[i] = startPos;
_poses[i] = sum;
sum += cnt;
counts[i] = sum;
}
static const int kNumDistanceLowDirectBitsForBigDict = 7;
static const int kNumDistanceLowDirectBitsForSmallDict = 6;
// counts[0] += sum;
static const int kNumBitsInByte = 8;
if (startPos != 0)
return false;
// static const int kLevelStructuresNumberFieldSize = kNumBitsInByte;
static const int kLevelStructuresNumberAdditionalValue = 1;
for (sym = 0; sym < numSymbols; sym++)
{
unsigned len = lens[sym];
if (len != 0)
_symbols[--counts[len]] = (Byte)sym;
}
static const int kNumLevelStructureLevelBits = 4;
static const int kLevelStructureLevelAdditionalValue = 1;
static const int kNumLevelStructureRepNumberBits = 4;
static const int kLevelStructureRepNumberAdditionalValue = 1;
return true;
}
static const int kLiteralTableSize = (1 << kNumBitsInByte);
static const int kDistanceTableSize = 64;
static const int kLengthTableSize = 64;
static const UInt32 kHistorySize =
(1 << MyMax(kNumDistanceLowDirectBitsForBigDict,
kNumDistanceLowDirectBitsForSmallDict)) *
kDistanceTableSize; // = 8 KB;
static const int kNumAdditionalLengthBits = 8;
static const UInt32 kMatchMinLenWhenLiteralsOn = 3;
static const UInt32 kMatchMinLenWhenLiteralsOff = 2;
static const UInt32 kMatchMinLenMax = MyMax(kMatchMinLenWhenLiteralsOn,
kMatchMinLenWhenLiteralsOff); // 3
// static const UInt32 kMatchMaxLenMax = kMatchMinLenMax + (kLengthTableSize - 1) + (1 << kNumAdditionalLengthBits) - 1; // or 2
enum
UInt32 CHuffmanDecoder::Decode(CInBit *inStream) const throw()
{
kMatchId = 0,
kLiteralId = 1
};
UInt32 val = inStream->GetValue(kNumHuffmanBits);
unsigned numBits;
for (numBits = 1; val < _limits[numBits]; numBits++);
UInt32 sym = _symbols[_poses[numBits] + ((val - _limits[numBits]) >> (kNumHuffmanBits - numBits))];
inStream->MovePos(numBits);
return sym;
}
static const unsigned kNumLenDirectBits = 8;
static const unsigned kNumDistDirectBitsSmall = 6;
static const unsigned kNumDistDirectBitsBig = 7;
static const unsigned kLitTableSize = (1 << 8);
static const unsigned kDistTableSize = 64;
static const unsigned kLenTableSize = 64;
static const UInt32 kHistorySize = (1 << kNumDistDirectBitsBig) * kDistTableSize; // 8 KB
CCoder::CCoder():
m_LiteralDecoder(kLiteralTableSize),
m_LengthDecoder(kLengthTableSize),
m_DistanceDecoder(kDistanceTableSize)
{
}
_fullStreamMode(false),
_flags(0)
{}
/*
void CCoder::ReleaseStreams()
{
m_OutWindowStream.ReleaseStream();
m_InBitStream.ReleaseStream();
}
*/
bool CCoder::ReadLevelItems(NImplode::NHuffman::CDecoder &decoder,
Byte *levels, int numLevelItems)
bool CCoder::BuildHuff(CHuffmanDecoder &decoder, unsigned numSymbols)
{
int numCodedStructures = m_InBitStream.ReadBits(kNumBitsInByte) +
kLevelStructuresNumberAdditionalValue;
int currentIndex = 0;
for (int i = 0; i < numCodedStructures; i++)
Byte levels[kMaxHuffTableSize];
unsigned numRecords = (unsigned)_inBitStream.ReadAlignedByte() + 1;
unsigned index = 0;
do
{
int level = m_InBitStream.ReadBits(kNumLevelStructureLevelBits) +
kLevelStructureLevelAdditionalValue;
int rep = m_InBitStream.ReadBits(kNumLevelStructureRepNumberBits) +
kLevelStructureRepNumberAdditionalValue;
if (currentIndex + rep > numLevelItems)
throw CException(CException::kData);
for (int j = 0; j < rep; j++)
levels[currentIndex++] = (Byte)level;
}
if (currentIndex != numLevelItems)
return false;
return decoder.SetCodeLengths(levels);
}
bool CCoder::ReadTables(void)
{
if (m_LiteralsOn)
{
Byte literalLevels[kLiteralTableSize];
if (!ReadLevelItems(m_LiteralDecoder, literalLevels, kLiteralTableSize))
unsigned b = (unsigned)_inBitStream.ReadAlignedByte();
Byte level = (Byte)((b & 0xF) + 1);
unsigned rep = ((unsigned)b >> 4) + 1;
if (index + rep > numSymbols)
return false;
for (unsigned j = 0; j < rep; j++)
levels[index++] = level;
}
while (--numRecords);
Byte lengthLevels[kLengthTableSize];
if (!ReadLevelItems(m_LengthDecoder, lengthLevels, kLengthTableSize))
if (index != numSymbols)
return false;
Byte distanceLevels[kDistanceTableSize];
return ReadLevelItems(m_DistanceDecoder, distanceLevels, kDistanceTableSize);
return decoder.Build(levels, numSymbols);
}
/*
class CCoderReleaser
{
CCoder *m_Coder;
public:
CCoderReleaser(CCoder *coder): m_Coder(coder) {}
~CCoderReleaser() { m_Coder->ReleaseStreams(); }
};
*/
HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
if (!m_InBitStream.Create(1 << 20))
if (!_inBitStream.Create(1 << 18))
return E_OUTOFMEMORY;
if (!m_OutWindowStream.Create(kHistorySize))
if (!_outWindowStream.Create(kHistorySize << 1)) // 16 KB
return E_OUTOFMEMORY;
if (outSize == NULL)
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;
m_OutWindowStream.SetStream(outStream);
m_OutWindowStream.Init(false);
m_InBitStream.SetStream(inStream);
m_InBitStream.Init();
// CCoderReleaser coderReleaser(this);
if (!ReadTables())
return S_FALSE;
while (pos < unPackSize)
{
if (progress != NULL && pos % (1 << 16) == 0)
if (progress && (pos - prevProgress) >= (1 << 18))
{
UInt64 packSize = m_InBitStream.GetProcessedSize();
const UInt64 packSize = _inBitStream.GetProcessedSize();
RINOK(progress->SetRatioInfo(&packSize, &pos));
prevProgress = pos;
}
if (m_InBitStream.ReadBits(1) == kMatchId) // match
if (_inBitStream.ReadBits(1) != 0)
{
UInt32 lowDistBits = m_InBitStream.ReadBits(m_NumDistanceLowDirectBits);
UInt32 distance = m_DistanceDecoder.DecodeSymbol(&m_InBitStream);
if (distance >= kDistanceTableSize)
return S_FALSE;
distance = (distance << m_NumDistanceLowDirectBits) + lowDistBits;
UInt32 lengthSymbol = m_LengthDecoder.DecodeSymbol(&m_InBitStream);
if (lengthSymbol >= kLengthTableSize)
return S_FALSE;
UInt32 length = lengthSymbol + m_MinMatchLength;
if (lengthSymbol == kLengthTableSize - 1) // special symbol = 63
length += m_InBitStream.ReadBits(kNumAdditionalLengthBits);
while (distance >= pos && length > 0)
Byte b;
if (literalsOn)
{
m_OutWindowStream.PutByte(0);
pos++;
length--;
UInt32 sym = _litDecoder.Decode(&_inBitStream);
// if (sym >= kLitTableSize) break;
b = (Byte)sym;
}
if (length > 0)
m_OutWindowStream.CopyBlock(distance, length);
pos += length;
else
b = (Byte)_inBitStream.ReadBits(8);
_outWindowStream.PutByte(b);
pos++;
}
else
{
Byte b;
if (m_LiteralsOn)
UInt32 lowDistBits = _inBitStream.ReadBits(numDistDirectBits);
UInt32 dist = _distDecoder.Decode(&_inBitStream);
// if (dist >= kDistTableSize) break;
dist = (dist << numDistDirectBits) + lowDistBits;
UInt32 len = _lenDecoder.Decode(&_inBitStream);
// if (len >= kLenTableSize) break;
if (len == kLenTableSize - 1)
len += _inBitStream.ReadBits(kNumLenDirectBits);
len += minMatchLen;
{
UInt32 temp = m_LiteralDecoder.DecodeSymbol(&m_InBitStream);
if (temp >= kLiteralTableSize)
return S_FALSE;
b = (Byte)temp;
const UInt64 limit = unPackSize - pos;
if (len > limit)
{
moreOut = true;
len = (UInt32)limit;
}
}
while (dist >= pos && len != 0)
{
_outWindowStream.PutByte(0);
pos++;
len--;
}
if (len != 0)
{
_outWindowStream.CopyBlock(dist, len);
pos += len;
}
else
b = (Byte)m_InBitStream.ReadBits(kNumBitsInByte);
m_OutWindowStream.PutByte(b);
pos++;
}
}
if (pos > unPackSize)
return S_FALSE;
return m_OutWindowStream.Flush();
HRESULT res = _outWindowStream.Flush();
if (res == S_OK)
{
if (_fullStreamMode)
{
if (moreOut)
res = S_FALSE;
if (inSize && *inSize != _inBitStream.GetProcessedSize())
res = S_FALSE;
}
if (pos != unPackSize)
res = S_FALSE;
}
return res;
}
STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
// catch(const CInBufferException &e) { return e.ErrorCode; }
// catch(const CLzOutWindowException &e) { return e.ErrorCode; }
catch(const CSystemException &e) { return e.ErrorCode; }
catch(...) { return S_FALSE; }
}
STDMETHODIMP CCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
{
if (size < 1)
return E_INVALIDARG;
Byte flag = data[0];
m_BigDictionaryOn = ((flag & 2) != 0);
m_NumDistanceLowDirectBits = m_BigDictionaryOn ?
kNumDistanceLowDirectBitsForBigDict:
kNumDistanceLowDirectBitsForSmallDict;
m_LiteralsOn = ((flag & 4) != 0);
m_MinMatchLength = m_LiteralsOn ?
kMatchMinLenWhenLiteralsOn :
kMatchMinLenWhenLiteralsOff;
if (size == 0)
return E_NOTIMPL;
_flags = data[0];
return S_OK;
}
STDMETHODIMP CCoder::SetFinishMode(UInt32 finishMode)
{
_fullStreamMode = (finishMode != 0);
return S_OK;
}
STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)
{
*value = _inBitStream.GetProcessedSize();
return S_OK;
}

View File

@@ -7,48 +7,65 @@
#include "../ICoder.h"
#include "ImplodeHuffmanDecoder.h"
#include "../Common/InBuffer.h"
#include "BitlDecoder.h"
#include "LzOutWindow.h"
namespace NCompress {
namespace NImplode {
namespace NDecoder {
typedef NBitl::CDecoder<CInBuffer> CInBit;
const unsigned kNumHuffmanBits = 16;
const unsigned kMaxHuffTableSize = 1 << 8;
class CHuffmanDecoder
{
UInt32 _limits[kNumHuffmanBits + 1];
UInt32 _poses[kNumHuffmanBits + 1];
Byte _symbols[kMaxHuffTableSize];
public:
bool Build(const Byte *lens, unsigned numSymbols) throw();
UInt32 Decode(CInBit *inStream) const throw();
};
class CCoder:
public ICompressCoder,
public ICompressSetDecoderProperties2,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public CMyUnknownImp
{
CLzOutWindow m_OutWindowStream;
NBitl::CDecoder<CInBuffer> m_InBitStream;
CLzOutWindow _outWindowStream;
CInBit _inBitStream;
NImplode::NHuffman::CDecoder m_LiteralDecoder;
NImplode::NHuffman::CDecoder m_LengthDecoder;
NImplode::NHuffman::CDecoder m_DistanceDecoder;
CHuffmanDecoder _litDecoder;
CHuffmanDecoder _lenDecoder;
CHuffmanDecoder _distDecoder;
bool m_BigDictionaryOn;
bool m_LiteralsOn;
Byte _flags;
bool _fullStreamMode;
int m_NumDistanceLowDirectBits;
UInt32 m_MinMatchLength;
bool ReadLevelItems(NImplode::NHuffman::CDecoder &table, Byte *levels, int numLevelItems);
bool ReadTables();
void DeCodeLevelTable(Byte *newLevels, int numLevels);
public:
CCoder();
MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
// void ReleaseStreams();
bool BuildHuff(CHuffmanDecoder &table, unsigned numSymbols);
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
public:
MY_UNKNOWN_IMP3(
ICompressSetDecoderProperties2,
ICompressSetFinishMode,
ICompressGetInStreamProcessedSize)
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
CCoder();
};
}}}

View File

@@ -1,89 +1,3 @@
// ImplodeHuffmanDecoder.cpp
#include "StdAfx.h"
#include "ImplodeHuffmanDecoder.h"
namespace NCompress {
namespace NImplode {
namespace NHuffman {
CDecoder::CDecoder(UInt32 numSymbols):
m_NumSymbols(numSymbols)
{
m_Symbols = new UInt32[m_NumSymbols];
}
CDecoder::~CDecoder()
{
delete []m_Symbols;
}
bool CDecoder::SetCodeLengths(const Byte *codeLengths)
{
// unsigned lenCounts[kNumBitsInLongestCode + 1], tmpPositions[kNumBitsInLongestCode + 1];
unsigned lenCounts[kNumBitsInLongestCode + 2], tmpPositions[kNumBitsInLongestCode + 1];
unsigned i;
for (i = 0; i <= kNumBitsInLongestCode; i++)
lenCounts[i] = 0;
UInt32 symbolIndex;
for (symbolIndex = 0; symbolIndex < m_NumSymbols; symbolIndex++)
lenCounts[codeLengths[symbolIndex]]++;
// lenCounts[0] = 0;
// tmpPositions[0] = m_Positions[0] = m_Limitits[0] = 0;
m_Limitits[kNumBitsInLongestCode + 1] = 0;
m_Positions[kNumBitsInLongestCode + 1] = 0;
lenCounts[kNumBitsInLongestCode + 1] = 0;
UInt32 startPos = 0;
static const UInt32 kMaxValue = (1 << kNumBitsInLongestCode);
for (i = kNumBitsInLongestCode; i > 0; i--)
{
startPos += lenCounts[i] << (kNumBitsInLongestCode - i);
if (startPos > kMaxValue)
return false;
m_Limitits[i] = startPos;
m_Positions[i] = m_Positions[i + 1] + lenCounts[i + 1];
tmpPositions[i] = m_Positions[i] + lenCounts[i];
}
// if _ZIP_MODE do not throw exception for trees containing only one node
// #ifndef _ZIP_MODE
if (startPos != kMaxValue)
return false;
// #endif
for (symbolIndex = 0; symbolIndex < m_NumSymbols; symbolIndex++)
if (codeLengths[symbolIndex] != 0)
m_Symbols[--tmpPositions[codeLengths[symbolIndex]]] = symbolIndex;
return true;
}
UInt32 CDecoder::DecodeSymbol(CInBit *inStream)
{
UInt32 numBits = 0;
UInt32 value = inStream->GetValue(kNumBitsInLongestCode);
unsigned i;
for (i = kNumBitsInLongestCode; i > 0; i--)
{
if (value < m_Limitits[i])
{
numBits = i;
break;
}
}
if (i == 0)
return 0xFFFFFFFF;
inStream->MovePos(numBits);
UInt32 index = m_Positions[numBits] +
((value - m_Limitits[numBits + 1]) >> (kNumBitsInLongestCode - numBits));
if (index >= m_NumSymbols)
return 0xFFFFFFFF;
return m_Symbols[index];
}
}}}

View File

@@ -3,32 +3,4 @@
#ifndef __IMPLODE_HUFFMAN_DECODER_H
#define __IMPLODE_HUFFMAN_DECODER_H
#include "../Common/InBuffer.h"
#include "BitlDecoder.h"
namespace NCompress {
namespace NImplode {
namespace NHuffman {
const unsigned kNumBitsInLongestCode = 16;
typedef NBitl::CDecoder<CInBuffer> CInBit;
class CDecoder
{
UInt32 m_Limitits[kNumBitsInLongestCode + 2]; // m_Limitits[i] = value limit for symbols with length = i
UInt32 m_Positions[kNumBitsInLongestCode + 2]; // m_Positions[i] = index in m_Symbols[] of first symbol with length = i
UInt32 m_NumSymbols; // number of symbols in m_Symbols
UInt32 *m_Symbols; // symbols: at first with len=1 then 2, ... 15.
public:
CDecoder(UInt32 numSymbols);
~CDecoder();
bool SetCodeLengths(const Byte *codeLengths);
UInt32 DecodeSymbol(CInBit *inStream);
};
}}}
#endif

View File

@@ -15,7 +15,7 @@ static HRESULT SResToHRESULT(SRes res)
case SZ_OK: return S_OK;
case SZ_ERROR_MEM: return E_OUTOFMEMORY;
case SZ_ERROR_PARAM: return E_INVALIDARG;
// case SZ_ERROR_PROGRESS: return E_ABORT;
case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
case SZ_ERROR_DATA: return S_FALSE;
}
return E_FAIL;
@@ -26,30 +26,31 @@ namespace NLzma2 {
CDecoder::CDecoder():
_inBuf(NULL),
_inBufSize(0),
_inBufSizeNew(1 << 20),
_outStepSize(1 << 22),
_finishMode(false),
_outSizeDefined(false),
_finishMode(false)
_outStep(1 << 22),
_inBufSize(0),
_inBufSizeNew(1 << 20)
{
Lzma2Dec_Construct(&_state);
}
STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; }
STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStepSize = size; return S_OK; }
CDecoder::~CDecoder()
{
Lzma2Dec_Free(&_state, &g_Alloc);
MidFree(_inBuf);
}
STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; }
STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
{
if (size != 1)
return E_NOTIMPL;
RINOK(SResToHRESULT(Lzma2Dec_Allocate(&_state, prop[0], &g_Alloc)));
if (!_inBuf || _inBufSize != _inBufSizeNew)
{
MidFree(_inBuf);
@@ -63,9 +64,6 @@ STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
return S_OK;
}
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) { *value = _inSizeProcessed; return S_OK; }
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
{
@@ -73,191 +71,197 @@ STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
_outSize = 0;
if (_outSizeDefined)
_outSize = *outSize;
_inPos = _inLim = 0;
_inProcessed = 0;
_outProcessed = 0;
Lzma2Dec_Init(&_state);
_inPos = _inSize = 0;
_inSizeProcessed = _outSizeProcessed = 0;
return S_OK;
}
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
{
_finishMode = (finishMode != 0);
return S_OK;
}
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
ISequentialOutStream *outStream, const UInt64 *inSize,
const UInt64 *outSize, ICompressProgressInfo *progress)
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
{
*value = _inProcessed;
return S_OK;
}
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
if (!_inBuf)
return S_FALSE;
SetOutStreamSize(outSize);
UInt32 step = _outStepSize;
const UInt32 kOutStepSize_Min = 1 << 12;
if (step < kOutStepSize_Min)
step = kOutStepSize_Min;
SizeT wrPos = _state.decoder.dicPos;
SizeT next = (_state.decoder.dicBufSize - _state.decoder.dicPos < step) ?
_state.decoder.dicBufSize :
_state.decoder.dicPos + step;
HRESULT hres = S_OK;
HRESULT readRes = S_OK;
for (;;)
{
if (_inPos == _inSize)
if (_inPos == _inLim && readRes == S_OK)
{
_inPos = _inSize = 0;
hres = inStream->Read(_inBuf, _inBufSize, &_inSize);
if (hres != S_OK)
break;
_inPos = _inLim = 0;
readRes = inStream->Read(_inBuf, _inBufSize, &_inLim);
}
const SizeT dicPos = _state.decoder.dicPos;
SizeT size;
{
SizeT next = _state.decoder.dicBufSize;
if (next - wrPos > _outStep)
next = wrPos + _outStep;
size = next - dicPos;
}
SizeT dicPos = _state.decoder.dicPos;
SizeT curSize = next - dicPos;
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
if (_outSizeDefined)
{
const UInt64 rem = _outSize - _outSizeProcessed;
if (curSize >= rem)
const UInt64 rem = _outSize - _outProcessed;
if (size >= rem)
{
curSize = (SizeT)rem;
size = (SizeT)rem;
if (_finishMode)
finishMode = LZMA_FINISH_END;
}
}
SizeT inSizeProcessed = _inSize - _inPos;
SizeT inProcessed = _inLim - _inPos;
ELzmaStatus status;
SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
SRes res = Lzma2Dec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status);
_inPos += (UInt32)inSizeProcessed;
_inSizeProcessed += inSizeProcessed;
SizeT outSizeProcessed = _state.decoder.dicPos - dicPos;
_outSizeProcessed += outSizeProcessed;
_inPos += (UInt32)inProcessed;
_inProcessed += inProcessed;
const SizeT outProcessed = _state.decoder.dicPos - dicPos;
_outProcessed += outProcessed;
bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0
|| status == LZMA_STATUS_FINISHED_WITH_MARK);
bool outFinished = (_outSizeDefined && _outSizeProcessed >= _outSize);
bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);
if (res != 0
|| _state.decoder.dicPos >= next
|| finished
|| outFinished)
bool needStop = (res != 0
|| (inProcessed == 0 && outProcessed == 0)
|| status == LZMA_STATUS_FINISHED_WITH_MARK
|| (!_finishMode && outFinished));
if (needStop || outProcessed >= size)
{
HRESULT res2 = WriteStream(outStream, _state.decoder.dic + wrPos, _state.decoder.dicPos - wrPos);
if (_state.decoder.dicPos == _state.decoder.dicBufSize)
_state.decoder.dicPos = 0;
wrPos = _state.decoder.dicPos;
next = (_state.decoder.dicBufSize - _state.decoder.dicPos < step) ?
_state.decoder.dicBufSize :
_state.decoder.dicPos + step;
if (res != 0)
return S_FALSE;
RINOK(res2);
if (finished)
if (needStop)
{
if (res != 0)
return S_FALSE;
if (status == LZMA_STATUS_FINISHED_WITH_MARK)
{
if (_finishMode && inSize && *inSize != _inSizeProcessed)
return S_FALSE;
if (finishMode == LZMA_FINISH_END && !outFinished)
return S_FALSE;
return S_OK;
if (_finishMode)
{
if (inSize && *inSize != _inProcessed)
return S_FALSE;
if (_outSizeDefined && _outSize != _outProcessed)
return S_FALSE;
}
return readRes;
}
return (finishMode == LZMA_FINISH_END) ? S_FALSE : S_OK;
}
if (outFinished && finishMode == LZMA_FINISH_ANY)
return S_OK;
if (!_finishMode && outFinished)
return readRes;
return S_FALSE;
}
}
if (progress)
{
RINOK(progress->SetRatioInfo(&_inSizeProcessed, &_outSizeProcessed));
RINOK(progress->SetRatioInfo(&_inProcessed, &_outProcessed));
}
}
HRESULT res2 = WriteStream(outStream, _state.decoder.dic + wrPos, _state.decoder.dicPos - wrPos);
if (hres != S_OK)
return hres;
return res2;
}
#ifndef NO_READ_FROM_CODER
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
{
UInt32 totalProcessed = 0;
if (processedSize)
*processedSize = 0;
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
if (_outSizeDefined)
{
const UInt64 rem = _outSize - _outProcessed;
if (size >= rem)
{
size = (UInt32)rem;
if (_finishMode)
finishMode = LZMA_FINISH_END;
}
}
HRESULT readRes = S_OK;
for (;;)
{
if (_inPos == _inSize)
if (_inPos == _inLim && readRes == S_OK)
{
_inPos = _inSize = 0;
RINOK(_inStream->Read(_inBuf, _inBufSize, &_inSize));
_inPos = _inLim = 0;
readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
}
SizeT inProcessed = _inLim - _inPos;
SizeT outProcessed = size;
ELzmaStatus status;
SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
_inBuf + _inPos, &inProcessed, finishMode, &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)
{
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
if (_outSizeDefined)
{
const UInt64 rem = _outSize - _outSizeProcessed;
if (rem <= size)
{
size = (UInt32)rem;
if (_finishMode)
finishMode = LZMA_FINISH_END;
}
}
SizeT outProcessed = size;
SizeT inProcessed = _inSize - _inPos;
ELzmaStatus status;
SRes res = Lzma2Dec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
_inBuf + _inPos, &inProcessed, finishMode, &status);
_inPos += (UInt32)inProcessed;
_inSizeProcessed += inProcessed;
_outSizeProcessed += outProcessed;
size -= (UInt32)outProcessed;
data = (Byte *)data + outProcessed;
totalProcessed += (UInt32)outProcessed;
if (processedSize)
*processedSize = totalProcessed;
if (res != SZ_OK)
{
if (totalProcessed != 0)
return S_OK;
return SResToHRESULT(res);
}
if (inProcessed == 0 && outProcessed == 0)
return S_OK;
if (status == LZMA_STATUS_FINISHED_WITH_MARK)
return S_OK;
if (outProcessed != 0)
{
if (finishMode != LZMA_FINISH_END || _outSize != _outSizeProcessed)
return S_OK;
}
if (_finishMode && _outSizeDefined && _outProcessed >= _outSize)
return S_FALSE;
return readRes;
}
*/
if (inProcessed == 0 && outProcessed == 0)
return readRes;
}
}

View File

@@ -6,7 +6,6 @@
#include "../../../C/Lzma2Dec.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
@@ -25,25 +24,23 @@ class CDecoder:
#endif
public CMyUnknownImp
{
CMyComPtr<ISequentialInStream> _inStream;
Byte *_inBuf;
UInt32 _inPos;
UInt32 _inSize;
UInt32 _inLim;
bool _finishMode;
bool _outSizeDefined;
UInt64 _outSize;
UInt64 _inSizeProcessed;
UInt64 _outSizeProcessed;
UInt64 _inProcessed;
UInt64 _outProcessed;
UInt32 _outStep;
UInt32 _inBufSize;
UInt32 _inBufSizeNew;
UInt32 _outStepSize;
CLzma2Dec _state;
public:
public:
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
@@ -59,28 +56,27 @@ public:
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
#ifndef NO_READ_FROM_CODER
private:
CMyComPtr<ISequentialInStream> _inStream;
public:
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
STDMETHOD(ReleaseInStream)();
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
#ifndef NO_READ_FROM_CODER
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
#endif
CDecoder();
virtual ~CDecoder();
};
}}

View File

@@ -82,11 +82,15 @@ STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
{
CSeqInStreamWrap inWrap(inStream);
CSeqOutStreamWrap outWrap(outStream);
CCompressProgressWrap progressWrap(progress);
CSeqInStreamWrap inWrap;
CSeqOutStreamWrap outWrap;
CCompressProgressWrap progressWrap;
inWrap.Init(inStream);
outWrap.Init(outStream);
progressWrap.Init(progress);
SRes res = Lzma2Enc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL);
SRes res = Lzma2Enc_Encode(_encoder, &outWrap.vt, &inWrap.vt, progress ? &progressWrap.vt : NULL);
if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
return inWrap.Res;
if (res == SZ_ERROR_WRITE && outWrap.Res != S_OK)

View File

@@ -24,14 +24,19 @@ static HRESULT SResToHRESULT(SRes res)
namespace NCompress {
namespace NLzma {
CDecoder::CDecoder(): _inBuf(0), _propsWereSet(false), _outSizeDefined(false),
_inBufSize(1 << 20),
_outBufSize(1 << 22),
CDecoder::CDecoder():
_inBuf(NULL),
_lzmaStatus(LZMA_STATUS_NOT_SPECIFIED),
FinishStream(false),
NeedMoreInput(false)
_propsWereSet(false),
_outSizeDefined(false),
_outStep(1 << 22),
_inBufSize(0),
_inBufSizeNew(1 << 20)
{
_inSizeProcessed = 0;
_inPos = _inSize = 0;
_inProcessed = 0;
_inPos = _inLim = 0;
LzmaDec_Construct(&_state);
}
@@ -41,22 +46,24 @@ CDecoder::~CDecoder()
MyFree(_inBuf);
}
STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }
STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; }
STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; }
STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }
HRESULT CDecoder::CreateInputBuffer()
{
if (_inBuf == 0 || _inBufSize != _inBufSizeAllocated)
if (!_inBuf || _inBufSizeNew != _inBufSize)
{
MyFree(_inBuf);
_inBuf = (Byte *)MyAlloc(_inBufSize);
if (_inBuf == 0)
_inBufSize = 0;
_inBuf = (Byte *)MyAlloc(_inBufSizeNew);
if (!_inBuf)
return E_OUTOFMEMORY;
_inBufSizeAllocated = _inBufSize;
_inBufSize = _inBufSizeNew;
}
return S_OK;
}
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
{
RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_Alloc)));
@@ -64,203 +71,266 @@ STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
return CreateInputBuffer();
}
void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)
{
_outSizeDefined = (outSize != NULL);
_outSize = 0;
if (_outSizeDefined)
_outSize = *outSize;
_outSizeProcessed = 0;
_wrPos = 0;
_outProcessed = 0;
_lzmaStatus = LZMA_STATUS_NOT_SPECIFIED;
LzmaDec_Init(&_state);
}
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
{
_inSizeProcessed = 0;
_inPos = _inSize = 0;
NeedMoreInput = false;
_inProcessed = 0;
_inPos = _inLim = 0;
SetOutStreamSizeResume(outSize);
return S_OK;
}
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
{
FinishStream = (finishMode != 0);
return S_OK;
}
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
{
*value = _inProcessed;
return S_OK;
}
HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
{
if (_inBuf == 0 || !_propsWereSet)
if (!_inBuf || !_propsWereSet)
return S_FALSE;
const UInt64 startInProgress = _inProcessed;
SizeT wrPos = _state.dicPos;
HRESULT readRes = S_OK;
UInt64 startInProgress = _inSizeProcessed;
SizeT next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize);
for (;;)
{
if (_inPos == _inSize)
if (_inPos == _inLim && readRes == S_OK)
{
_inPos = _inSize = 0;
RINOK(inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
_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;
}
SizeT dicPos = _state.dicPos;
SizeT curSize = next - dicPos;
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
if (_outSizeDefined)
{
const UInt64 rem = _outSize - _outSizeProcessed;
if (rem <= curSize)
const UInt64 rem = _outSize - _outProcessed;
if (size >= rem)
{
curSize = (SizeT)rem;
size = (SizeT)rem;
if (FinishStream)
finishMode = LZMA_FINISH_END;
}
}
SizeT inSizeProcessed = _inSize - _inPos;
SizeT inProcessed = _inLim - _inPos;
ELzmaStatus status;
SRes res = LzmaDec_DecodeToDic(&_state, dicPos + curSize, _inBuf + _inPos, &inSizeProcessed, finishMode, &status);
SRes res = LzmaDec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status);
_inPos += (UInt32)inSizeProcessed;
_inSizeProcessed += inSizeProcessed;
SizeT outSizeProcessed = _state.dicPos - dicPos;
_outSizeProcessed += outSizeProcessed;
_lzmaStatus = status;
_inPos += (UInt32)inProcessed;
_inProcessed += inProcessed;
const SizeT outProcessed = _state.dicPos - dicPos;
_outProcessed += outProcessed;
bool finished = (inSizeProcessed == 0 && outSizeProcessed == 0);
bool stopDecoding = (_outSizeDefined && _outSizeProcessed >= _outSize);
// we check for LZMA_STATUS_NEEDS_MORE_INPUT to allow RangeCoder initialization, if (_outSizeDefined && _outSize == 0)
bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);
if (res != 0 || _state.dicPos == next || finished || stopDecoding)
bool needStop = (res != 0
|| (inProcessed == 0 && outProcessed == 0)
|| status == LZMA_STATUS_FINISHED_WITH_MARK
|| (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT));
if (needStop || outProcessed >= size)
{
HRESULT res2 = WriteStream(outStream, _state.dic + _wrPos, _state.dicPos - _wrPos);
HRESULT res2 = WriteStream(outStream, _state.dic + wrPos, _state.dicPos - wrPos);
_wrPos = _state.dicPos;
if (_state.dicPos == _state.dicBufSize)
{
_state.dicPos = 0;
_wrPos = 0;
}
next = (_state.dicBufSize - _state.dicPos < _outBufSize) ? _state.dicBufSize : (_state.dicPos + _outBufSize);
if (res != 0)
return S_FALSE;
wrPos = _state.dicPos;
RINOK(res2);
if (stopDecoding)
if (needStop)
{
if (status == LZMA_STATUS_NEEDS_MORE_INPUT)
NeedMoreInput = true;
if (FinishStream &&
status != LZMA_STATUS_FINISHED_WITH_MARK &&
status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
if (res != 0)
return S_FALSE;
return S_OK;
}
if (finished)
{
if (status == LZMA_STATUS_NEEDS_MORE_INPUT)
NeedMoreInput = true;
return (status == LZMA_STATUS_FINISHED_WITH_MARK ? S_OK : 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)
{
UInt64 inSize = _inSizeProcessed - startInProgress;
RINOK(progress->SetRatioInfo(&inSize, &_outSizeProcessed));
const UInt64 inSize = _inProcessed - startInProgress;
RINOK(progress->SetRatioInfo(&inSize, &_outProcessed));
}
}
}
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
if (_inBuf == 0)
if (!_inBuf)
return E_INVALIDARG;
SetOutStreamSize(outSize);
return CodeSpec(inStream, outStream, progress);
HRESULT res = CodeSpec(inStream, outStream, progress);
if (res == S_OK)
if (FinishStream && inSize && *inSize != _inProcessed)
res = S_FALSE;
return res;
}
#ifndef NO_READ_FROM_CODER
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
do
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
if (_outSizeDefined)
{
if (_inPos == _inSize)
const UInt64 rem = _outSize - _outProcessed;
if (size >= rem)
{
_inPos = _inSize = 0;
RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
}
{
SizeT inProcessed = _inSize - _inPos;
if (_outSizeDefined)
{
const UInt64 rem = _outSize - _outSizeProcessed;
if (rem < size)
size = (UInt32)rem;
}
SizeT outProcessed = size;
ELzmaStatus status;
SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
_inBuf + _inPos, &inProcessed, LZMA_FINISH_ANY, &status);
_inPos += (UInt32)inProcessed;
_inSizeProcessed += inProcessed;
_outSizeProcessed += outProcessed;
size -= (UInt32)outProcessed;
data = (Byte *)data + outProcessed;
if (processedSize)
*processedSize += (UInt32)outProcessed;
RINOK(SResToHRESULT(res));
if (inProcessed == 0 && outProcessed == 0)
return S_OK;
size = (UInt32)rem;
if (FinishStream)
finishMode = LZMA_FINISH_END;
}
}
while (size != 0);
return S_OK;
HRESULT readRes = S_OK;
for (;;)
{
if (_inPos == _inLim && readRes == S_OK)
{
_inPos = _inLim = 0;
readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
}
SizeT inProcessed = _inLim - _inPos;
SizeT outProcessed = size;
ELzmaStatus status;
SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
_inBuf + _inPos, &inProcessed, finishMode, &status);
_lzmaStatus = status;
_inPos += (UInt32)inProcessed;
_inProcessed += inProcessed;
_outProcessed += outProcessed;
size -= (UInt32)outProcessed;
data = (Byte *)data + outProcessed;
if (processedSize)
*processedSize += (UInt32)outProcessed;
if (res != 0)
return S_FALSE;
/*
if (status == LZMA_STATUS_FINISHED_WITH_MARK)
return readRes;
if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)
{
if (FinishStream
&& _outSizeDefined && _outProcessed >= _outSize
&& status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
return S_FALSE;
return readRes;
}
*/
if (inProcessed == 0 && outProcessed == 0)
return readRes;
}
}
HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
{
SetOutStreamSizeResume(outSize);
return CodeSpec(_inStream, outStream, progress);
}
HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize)
{
RINOK(CreateInputBuffer());
if (processedSize)
*processedSize = 0;
while (size > 0)
HRESULT readRes = S_OK;
while (size != 0)
{
if (_inPos == _inSize)
if (_inPos == _inLim)
{
_inPos = _inSize = 0;
RINOK(_inStream->Read(_inBuf, _inBufSizeAllocated, &_inSize));
if (_inSize == 0)
_inPos = _inLim = 0;
if (readRes == S_OK)
readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
if (_inLim == 0)
break;
}
{
UInt32 curSize = _inSize - _inPos;
if (curSize > size)
curSize = size;
memcpy(data, _inBuf + _inPos, curSize);
_inPos += curSize;
_inSizeProcessed += curSize;
size -= curSize;
data = (Byte *)data + curSize;
if (processedSize)
*processedSize += curSize;
}
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 S_OK;
return readRes;
}
#endif

View File

@@ -15,6 +15,7 @@ class CDecoder:
public ICompressCoder,
public ICompressSetDecoderProperties2,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public ICompressSetBufSize,
#ifndef NO_READ_FROM_CODER
public ICompressSetInStream,
@@ -23,21 +24,26 @@ class CDecoder:
#endif
public CMyUnknownImp
{
CMyComPtr<ISequentialInStream> _inStream;
Byte *_inBuf;
UInt32 _inPos;
UInt32 _inSize;
UInt32 _inLim;
CLzmaDec _state;
ELzmaStatus _lzmaStatus;
public:
bool FinishStream; // set it before decoding, if you need to decode full LZMA stream
private:
bool _propsWereSet;
bool _outSizeDefined;
UInt64 _outSize;
UInt64 _inSizeProcessed;
UInt64 _outSizeProcessed;
UInt64 _inProcessed;
UInt64 _outProcessed;
UInt32 _inBufSizeAllocated;
UInt32 _outStep;
UInt32 _inBufSize;
UInt32 _outBufSize;
SizeT _wrPos;
UInt32 _inBufSizeNew;
HRESULT CreateInputBuffer();
HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
@@ -47,6 +53,7 @@ public:
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)
#ifndef NO_READ_FROM_CODER
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
@@ -60,11 +67,16 @@ public:
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
#ifndef NO_READ_FROM_CODER
private:
CMyComPtr<ISequentialInStream> _inStream;
public:
STDMETHOD(SetInStream)(ISequentialInStream *inStream);
STDMETHOD(ReleaseInStream)();
@@ -72,18 +84,24 @@ public:
HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize);
UInt64 GetInputProcessedSize() const { return _inSizeProcessed; }
#endif
bool FinishStream; // set it before decoding, if you need to decode full LZMA stream
bool NeedMoreInput; // it's set by decoder, if it needs more input data to decode stream
UInt64 GetInputProcessedSize() const { return _inProcessed; }
CDecoder();
virtual ~CDecoder();
UInt64 GetOutputProcessedSize() const { return _outSizeProcessed; }
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);
}
};
}}

View File

@@ -134,11 +134,16 @@ STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
{
CSeqInStreamWrap inWrap(inStream);
CSeqOutStreamWrap outWrap(outStream);
CCompressProgressWrap progressWrap(progress);
CSeqInStreamWrap inWrap;
CSeqOutStreamWrap outWrap;
CCompressProgressWrap progressWrap;
inWrap.Init(inStream);
outWrap.Init(outStream);
progressWrap.Init(progress);
SRes res = LzmaEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, progress ? &progressWrap.vt : NULL, &g_Alloc, &g_BigAlloc);
SRes res = LzmaEnc_Encode(_encoder, &outWrap.p, &inWrap.p, progress ? &progressWrap.p : NULL, &g_Alloc, &g_BigAlloc);
_inputProcessed = inWrap.Processed;
if (res == SZ_ERROR_READ && inWrap.Res != S_OK)
return inWrap.Res;

View File

@@ -30,7 +30,9 @@ public:
CEncoder();
virtual ~CEncoder();
UInt64 GetInputProcessedSize() const { return _inputProcessed; }
bool IsWriteEndMark() const { return LzmaEnc_IsWriteEndMark(_encoder) != 0; }
};
}}

View File

@@ -114,8 +114,8 @@ static void x86_Filter(Byte *data, UInt32 size, Int32 *history)
size -= 16;
const unsigned kSave = 6;
const Byte savedByte = data[size + kSave];
data[size + kSave] = 0xE8;
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
@@ -215,7 +215,7 @@ static void x86_Filter(Byte *data, UInt32 size, Int32 *history)
*target = i;
}
data[size + kSave] = savedByte;
data[(size_t)size + kSave] = savedByte;
}

View File

@@ -27,8 +27,8 @@ static void x86_Filter(Byte *data, UInt32 size, UInt32 processedSize, UInt32 tra
return;
size -= kResidue;
Byte save = data[size + 4];
data[size + 4] = 0xE8;
Byte save = data[(size_t)size + 4];
data[(size_t)size + 4] = 0xE8;
for (UInt32 i = 0;;)
{
@@ -57,7 +57,7 @@ static void x86_Filter(Byte *data, UInt32 size, UInt32 processedSize, UInt32 tra
}
}
data[size + 4] = save;
data[(size_t)size + 4] = save;
}

View File

@@ -11,11 +11,11 @@ struct CMtf8Encoder
{
Byte Buf[256];
unsigned FindAndMove(Byte v)
unsigned FindAndMove(Byte v) throw()
{
unsigned pos;
size_t pos;
for (pos = 0; Buf[pos] != v; pos++);
unsigned resPos = pos;
unsigned resPos = (unsigned)pos;
for (; pos >= 8; pos -= 8)
{
Buf[pos] = Buf[pos - 1];
@@ -39,9 +39,10 @@ struct CMtf8Decoder
{
Byte Buf[256];
void Init(int) {};
void StartInit() { memset(Buf, 0, sizeof(Buf)); }
void Add(unsigned pos, Byte val) { Buf[pos] = val; }
Byte GetHead() const { return Buf[0]; }
Byte GetAndMove(int pos)
Byte GetAndMove(unsigned pos)
{
Byte res = Buf[pos];
for (; pos >= 8; pos -= 8)
@@ -64,11 +65,11 @@ struct CMtf8Decoder
*/
#ifdef MY_CPU_64BIT
typedef UInt64 CMtfVar;
#define MTF_MOVS 3
typedef UInt64 CMtfVar;
#define MTF_MOVS 3
#else
typedef UInt32 CMtfVar;
#define MTF_MOVS 2
typedef UInt32 CMtfVar;
#define MTF_MOVS 2
#endif
#define MTF_MASK ((1 << MTF_MOVS) - 1)
@@ -81,13 +82,18 @@ struct CMtf8Decoder
void StartInit() { memset(Buf, 0, sizeof(Buf)); }
void Add(unsigned pos, Byte val) { Buf[pos >> MTF_MOVS] |= ((CMtfVar)val << ((pos & MTF_MASK) << 3)); }
Byte GetHead() const { return (Byte)Buf[0]; }
Byte GetAndMove(unsigned pos)
MY_FORCE_INLINE
Byte GetAndMove(unsigned pos) throw()
{
UInt32 lim = ((UInt32)pos >> MTF_MOVS);
pos = (pos & MTF_MASK) << 3;
CMtfVar prev = (Buf[lim] >> pos) & 0xFF;
UInt32 i = 0;
/*
if ((lim & 1) != 0)
{
CMtfVar next = Buf[0];
@@ -104,6 +110,16 @@ struct CMtf8Decoder
Buf[i + 1] = (n1 << 8) | (n0 >> (MTF_MASK << 3));
prev = (n1 >> (MTF_MASK << 3));
}
*/
for (; i < lim; i++)
{
CMtfVar n0 = Buf[i];
Buf[i ] = (n0 << 8) | prev;
prev = (n0 >> (MTF_MASK << 3));
}
CMtfVar next = Buf[i];
CMtfVar mask = (((CMtfVar)0x100 << pos) - 1);
Buf[i] = (next & ~mask) | (((next << 8) | prev) & mask);
@@ -117,7 +133,7 @@ class CMtf8Decoder
{
Byte SmallBuffer[kSmallSize];
int SmallSize;
Byte Counts[16];
int Counts[16];
int Size;
public:
Byte Buf[256];
@@ -140,6 +156,11 @@ public:
}
}
void Add(unsigned pos, Byte val)
{
Buf[pos] = val;
}
Byte GetAndMove(int pos)
{
if (pos < SmallSize)

View File

@@ -75,7 +75,7 @@ HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
int sym = 0;
for (i = 0; i != size; i++)
{
sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.p);
sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.vt);
if (_inStream.Extra || sym < 0)
break;
memStream[i] = (Byte)sym;
@@ -134,6 +134,13 @@ STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
return S_OK;
}
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
{
*value = _inStream.GetProcessed();
return S_OK;
}
#ifndef NO_READ_FROM_CODER
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)

View File

@@ -18,6 +18,7 @@ namespace NPpmd {
class CDecoder :
public ICompressCoder,
public ICompressSetDecoderProperties2,
public ICompressGetInStreamProcessedSize,
#ifndef NO_READ_FROM_CODER
public ICompressSetInStream,
public ICompressSetOutStreamSize,
@@ -42,19 +43,26 @@ public:
#ifndef NO_READ_FROM_CODER
CMyComPtr<ISequentialInStream> InSeqStream;
MY_UNKNOWN_IMP4(
ICompressSetDecoderProperties2,
ICompressSetInStream,
ICompressSetOutStreamSize,
ISequentialInStream)
#else
MY_UNKNOWN_IMP1(
ICompressSetDecoderProperties2)
#endif
MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
// MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
#ifndef NO_READ_FROM_CODER
MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
#endif
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
#ifndef NO_READ_FROM_CODER
@@ -66,7 +74,7 @@ public:
CDecoder(): _outBuf(NULL), _outSizeDefined(false)
{
Ppmd7z_RangeDec_CreateVTable(&_rangeDec);
_rangeDec.Stream = &_inStream.p;
_rangeDec.Stream = &_inStream.vt;
Ppmd7_Construct(&_ppmd);
}

View File

@@ -43,7 +43,7 @@ CEncoder::CEncoder():
_inBuf(NULL)
{
_props.Normalize(-1);
_rangeEnc.Stream = &_outStream.p;
_rangeEnc.Stream = &_outStream.vt;
Ppmd7_Construct(&_ppmd);
}

View File

@@ -15,7 +15,7 @@ namespace NPpmdZip {
CDecoder::CDecoder(bool fullFileMode):
_fullFileMode(fullFileMode)
{
_ppmd.Stream.In = &_inStream.p;
_ppmd.Stream.In = &_inStream.vt;
Ppmd8_Construct(&_ppmd);
}
@@ -25,7 +25,7 @@ CDecoder::~CDecoder()
}
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
if (!_outStream.Alloc())
return E_OUTOFMEMORY;
@@ -64,15 +64,21 @@ STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
bool wasFinished = false;
UInt64 processedSize = 0;
while (!outSize || processedSize < *outSize)
for (;;)
{
size_t size = kBufSize;
if (outSize != NULL)
if (outSize)
{
const UInt64 rem = *outSize - processedSize;
if (size > rem)
{
size = (size_t)rem;
if (size == 0)
break;
}
}
Byte *data = _outStream.Buf;
size_t i = 0;
int sym = 0;
@@ -84,6 +90,7 @@ STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
data[i] = (Byte)sym;
}
while (++i != size);
processedSize += i;
RINOK(WriteStream(outStream, _outStream.Buf, i));
@@ -99,13 +106,16 @@ STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
wasFinished = true;
break;
}
if (progress)
{
UInt64 inSize = _inStream.GetProcessed();
RINOK(progress->SetRatioInfo(&inSize, &processedSize));
const UInt64 inProccessed = _inStream.GetProcessed();
RINOK(progress->SetRatioInfo(&inProccessed, &processedSize));
}
}
RINOK(_inStream.Res);
if (_fullFileMode)
{
if (!wasFinished)
@@ -117,11 +127,29 @@ STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream
}
if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd))
return S_FALSE;
if (inSize && *inSize != _inStream.GetProcessed())
return S_FALSE;
}
return S_OK;
}
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
{
_fullFileMode = (finishMode != 0);
return S_OK;
}
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
{
*value = _inStream.GetProcessed();
return S_OK;
}
// ---------- Encoder ----------
void CEncProps::Normalize(int level)
@@ -206,7 +234,7 @@ STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIA
CEncoder::CEncoder()
{
_props.Normalize(-1);
_ppmd.Stream.Out = &_outStream.p;
_ppmd.Stream.Out = &_outStream.vt;
Ppmd8_Construct(&_ppmd);
}
@@ -248,10 +276,10 @@ STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream
RINOK(_outStream.Res);
}
processed += size;
if (progress != NULL)
if (progress)
{
UInt64 outSize = _outStream.GetProcessed();
RINOK(progress->SetRatioInfo(&processed, &outSize));
const UInt64 outProccessed = _outStream.GetProcessed();
RINOK(progress->SetRatioInfo(&processed, &outProccessed));
}
}
}

View File

@@ -31,8 +31,11 @@ struct CBuf
}
};
class CDecoder :
public ICompressCoder,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public CMyUnknownImp
{
CByteInBufWrap _inStream;
@@ -40,13 +43,20 @@ class CDecoder :
CPpmd8 _ppmd;
bool _fullFileMode;
public:
MY_UNKNOWN_IMP
MY_UNKNOWN_IMP2(
ICompressSetFinishMode,
ICompressGetInStreamProcessedSize)
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
CDecoder(bool fullFileMode);
~CDecoder();
};
struct CEncProps
{
UInt32 MemSizeMB;

View File

@@ -37,7 +37,7 @@ unsigned CModelDecoder::Decode(CRangeDecoder *rc)
unsigned i;
for (i = 1; Freqs[i] > threshold; i++);
rc->Decode(Freqs[i], Freqs[i - 1], Freqs[0]);
rc->Decode(Freqs[i], Freqs[(size_t)i - 1], Freqs[0]);
unsigned res = Vals[--i];
do
@@ -50,7 +50,7 @@ unsigned CModelDecoder::Decode(CRangeDecoder *rc)
{
ReorderCount = kReorderCount;
for (i = 0; i < NumItems; i++)
Freqs[i] = (UInt16)(((Freqs[i] - Freqs[i + 1]) + 1) >> 1);
Freqs[i] = (UInt16)(((Freqs[i] - Freqs[(size_t)i + 1]) + 1) >> 1);
for (i = 0; i < NumItems - 1; i++)
for (unsigned j = i + 1; j < NumItems; j++)
if (Freqs[i] < Freqs[j])
@@ -64,7 +64,7 @@ unsigned CModelDecoder::Decode(CRangeDecoder *rc)
}
do
Freqs[i] = (UInt16)(Freqs[i] + Freqs[i + 1]);
Freqs[i] = (UInt16)(Freqs[i] + Freqs[(size_t)i + 1]);
while (i--);
}
else
@@ -73,8 +73,8 @@ unsigned CModelDecoder::Decode(CRangeDecoder *rc)
do
{
Freqs[i] >>= 1;
if (Freqs[i] <= Freqs[i + 1])
Freqs[i] = (UInt16)(Freqs[i + 1] + 1);
if (Freqs[i] <= Freqs[(size_t)i + 1])
Freqs[i] = (UInt16)(Freqs[(size_t)i + 1] + 1);
}
while (i--);
}

View File

@@ -57,7 +57,7 @@ UInt32 CDecoder::DecodeNum(const UInt32 *posTab)
UInt32 num = m_InBitStream.GetValue(12);
for (;;)
{
UInt32 cur = (posTab[startPos + 1] - posTab[startPos]) << (12 - startPos);
UInt32 cur = (posTab[(size_t)startPos + 1] - posTab[startPos]) << (12 - startPos);
if (num < cur)
break;
startPos++;
@@ -149,7 +149,7 @@ HRESULT CDecoder::ShortLZ()
PlaceA[dist]--;
UInt32 lastDistance = ChSetA[(unsigned)distancePlace];
PlaceA[lastDistance]++;
ChSetA[(unsigned)distancePlace + 1] = lastDistance;
ChSetA[(size_t)(unsigned)distancePlace + 1] = lastDistance;
ChSetA[(unsigned)distancePlace] = dist;
}
len += 2;

View File

@@ -104,7 +104,8 @@ bool CDecoder::ReadTables(void)
m_TablesOK = false;
Byte levelLevels[kLevelTableSize];
Byte newLevels[kMaxTableSize];
Byte lens[kMaxTableSize];
m_AudioMode = (ReadBits(1) == 1);
if (ReadBits(1) == 0)
@@ -134,16 +135,29 @@ bool CDecoder::ReadTables(void)
UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
if (sym < kTableDirectLevels)
{
newLevels[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask);
lens[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask);
i++;
}
else
{
if (sym == kTableLevelRepNumber)
{
unsigned t = ReadBits(2) + 3;
for (unsigned reps = t; reps > 0 && i < numLevels; reps--, i++)
newLevels[i] = newLevels[i - 1];
unsigned num = ReadBits(2) + 3;
if (i == 0)
{
// return false;
continue; // original unRAR
}
num += i;
if (num > numLevels)
{
// return false;
num = numLevels; // original unRAR
}
Byte v = lens[(size_t)i - 1];
do
lens[i++] = v;
while (i < num);
}
else
{
@@ -154,8 +168,15 @@ bool CDecoder::ReadTables(void)
num = ReadBits(7) + 11;
else
return false;
for (; num > 0 && i < numLevels; num--)
newLevels[i++] = 0;
num += i;
if (num > numLevels)
{
// return false;
num = numLevels; // original unRAR
}
do
lens[i++] = 0;
while (i < num);
}
}
}
@@ -163,16 +184,16 @@ bool CDecoder::ReadTables(void)
if (m_AudioMode)
for (i = 0; i < m_NumChannels; i++)
{
RIF(m_MMDecoders[i].Build(&newLevels[i * kMMTableSize]));
RIF(m_MMDecoders[i].Build(&lens[i * kMMTableSize]));
}
else
{
RIF(m_MainDecoder.Build(&newLevels[0]));
RIF(m_DistDecoder.Build(&newLevels[kMainTableSize]));
RIF(m_LenDecoder.Build(&newLevels[kMainTableSize + kDistTableSize]));
RIF(m_MainDecoder.Build(&lens[0]));
RIF(m_DistDecoder.Build(&lens[kMainTableSize]));
RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize]));
}
memcpy(m_LastLevels, newLevels, kMaxTableSize);
memcpy(m_LastLevels, lens, kMaxTableSize);
m_TablesOK = true;
@@ -220,13 +241,11 @@ public:
bool CDecoder::DecodeMm(UInt32 pos)
{
while (pos-- > 0)
while (pos-- != 0)
{
UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
if (symbol == 256)
return true;
if (symbol >= kMMTableSize)
return false;
if (symbol >= 256)
return symbol == 256;
/*
Byte byPredict = m_Predictor.Predict();
Byte byReal = (Byte)(byPredict - (Byte)symbol);
@@ -254,6 +273,8 @@ bool CDecoder::DecodeLz(Int32 pos)
}
else if (sym >= kMatchNumber)
{
if (sym >= kMainTableSize)
return false;
sym -= kMatchNumber;
length = kNormalMatchMinLen + UInt32(kLenStart[sym]) +
m_InBitStream.ReadBits(kLenDirectBits[sym]);
@@ -302,10 +323,9 @@ bool CDecoder::DecodeLz(Int32 pos)
m_InBitStream.ReadBits(kLen2DistDirectBits[sym]);
length = 2;
}
else if (sym == kReadTableNumber)
else // (sym == kReadTableNumber)
return true;
else
return false;
m_RepDists[m_RepDistPtr++ & 3] = distance;
m_LastLength = length;
if (!m_OutWindowStream.CopyBlock(distance, length))

View File

@@ -44,15 +44,17 @@ static const UInt32 kVmCodeSizeMax = 1 << 16;
extern "C" {
static UInt32 Range_GetThreshold(void *pp, UInt32 total)
#define GET_RangeDecoder CRangeDecoder *p = CONTAINER_FROM_VTBL_CLS(pp, CRangeDecoder, vt);
static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total)
{
CRangeDecoder *p = (CRangeDecoder *)pp;
GET_RangeDecoder;
return p->Code / (p->Range /= total);
}
static void Range_Decode(void *pp, UInt32 start, UInt32 size)
static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size)
{
CRangeDecoder *p = (CRangeDecoder *)pp;
GET_RangeDecoder;
start *= p->Range;
p->Low += start;
p->Code -= start;
@@ -60,28 +62,28 @@ static void Range_Decode(void *pp, UInt32 start, UInt32 size)
p->Normalize();
}
static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0)
{
CRangeDecoder *p = (CRangeDecoder *)pp;
GET_RangeDecoder;
if (p->Code / (p->Range >>= 14) < size0)
{
Range_Decode(p, 0, size0);
Range_Decode(&p->vt, 0, size0);
return 0;
}
else
{
Range_Decode(p, size0, (1 << 14) - size0);
Range_Decode(&p->vt, size0, (1 << 14) - size0);
return 1;
}
}
}
CRangeDecoder::CRangeDecoder()
CRangeDecoder::CRangeDecoder() throw()
{
s.GetThreshold = Range_GetThreshold;
s.Decode = Range_Decode;
s.DecodeBit = Range_DecodeBit;
vt.GetThreshold = Range_GetThreshold;
vt.Decode = Range_Decode;
vt.DecodeBit = Range_DecodeBit;
}
CDecoder::CDecoder():
@@ -445,7 +447,7 @@ HRESULT CDecoder::InitPPM()
return S_OK;
}
int CDecoder::DecodePpmSymbol() { return Ppmd7_DecodeSymbol(&_ppmd, &m_InBitStream.s); }
int CDecoder::DecodePpmSymbol() { return Ppmd7_DecodeSymbol(&_ppmd, &m_InBitStream.vt); }
HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
{
@@ -545,6 +547,9 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
return InitPPM();
}
TablesRead = false;
TablesOK = false;
_lzMode = true;
PrevAlignBits = 0;
PrevAlignCount = 0;
@@ -597,7 +602,7 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
if (i == 0)
return S_FALSE;
for (; num > 0 && i < kTablesSizesSum; num--, i++)
newLevels[i] = newLevels[i - 1];
newLevels[i] = newLevels[(size_t)i - 1];
}
else
{
@@ -606,6 +611,7 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
}
}
}
TablesRead = true;
// original code has check here:
@@ -623,6 +629,9 @@ HRESULT CDecoder::ReadTables(bool &keepDecompressing)
RIF(m_LenDecoder.Build(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
memcpy(m_LastLevels, newLevels, kTablesSizesSum);
TablesOK = true;
return S_OK;
}
@@ -641,16 +650,15 @@ public:
HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
{
if (ReadBits(1) != 0)
if (ReadBits(1) == 0)
{
// old file
TablesRead = false;
return ReadTables(keepDecompressing);
// new file
keepDecompressing = false;
TablesRead = (ReadBits(1) == 0);
return S_OK;
}
// new file
keepDecompressing = false;
TablesRead = (ReadBits(1) == 0);
return S_OK;
TablesRead = false;
return ReadTables(keepDecompressing);
}
UInt32 kDistStart[kDistTableSize];
@@ -807,10 +815,12 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
return S_OK;
}
HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
{
_writtenFileSize = 0;
_unsupportedFilter = false;
if (!m_IsSolid)
{
_lzSize = 0;
@@ -825,6 +835,7 @@ HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
PpmError = true;
InitFilters();
}
if (!m_IsSolid || !TablesRead)
{
bool keepDecompressing;
@@ -838,6 +849,8 @@ HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
bool keepDecompressing;
if (_lzMode)
{
if (!TablesOK)
return S_FALSE;
RINOK(DecodeLZ(keepDecompressing))
}
else

View File

@@ -102,7 +102,7 @@ const UInt32 kBot = (1 << 15);
struct CRangeDecoder
{
IPpmd7_RangeDec s;
IPpmd7_RangeDec vt;
UInt32 Range;
UInt32 Code;
UInt32 Low;
@@ -130,7 +130,7 @@ public:
}
}
CRangeDecoder();
CRangeDecoder() throw();
};
struct CFilter: public NVm::CProgram
@@ -200,6 +200,7 @@ class CDecoder:
UInt32 PrevAlignCount;
bool TablesRead;
bool TablesOK;
CPpmd7 _ppmd;
int PpmEscChar;

View File

@@ -891,53 +891,47 @@ static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
}
}
static inline UInt32 ItaniumGetOpType(const Byte *data, unsigned bitPos)
{
return (data[bitPos >> 3] >> (bitPos & 7)) & 0xF;
}
static const Byte kCmdMasks[16] = {4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0};
static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset)
{
UInt32 curPos = 0;
if (dataSize <= 21)
return;
fileOffset >>= 4;
while (curPos < dataSize - 21)
dataSize -= 21;
dataSize += 15;
dataSize >>= 4;
dataSize += fileOffset;
do
{
int b = (data[0] & 0x1F) - 0x10;
if (b >= 0)
unsigned m = ((UInt32)0x334B0000 >> (data[0] & 0x1E)) & 3;
if (m)
{
Byte cmdMask = kCmdMasks[b];
if (cmdMask != 0)
for (unsigned i = 0; i < 3; i++)
if (cmdMask & (1 << i))
{
unsigned startPos = i * 41 + 18;
if (ItaniumGetOpType(data, startPos + 24) == 5)
{
const UInt32 kMask = 0xFFFFF;
Byte *p = data + (startPos >> 3);
UInt32 bitField = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16);
unsigned inBit = (startPos & 7);
UInt32 offset = (bitField >> inBit) & kMask;
UInt32 andMask = ~(kMask << inBit);
bitField = ((offset - fileOffset) & kMask) << inBit;
for (unsigned j = 0; j < 3; j++)
{
p[j] &= andMask;
p[j] |= bitField;
andMask >>= 8;
bitField >>= 8;
}
}
}
m++;
do
{
Byte *p = data + ((size_t)m * 5 - 8);
if (((p[3] >> m) & 15) == 5)
{
const UInt32 kMask = 0xFFFFF;
// UInt32 raw = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16);
UInt32 raw = GetUi32(p);
UInt32 v = raw >> m;
v -= fileOffset;
v &= kMask;
raw &= ~(kMask << m);
raw |= (v << m);
// p[0] = (Byte)raw; p[1] = (Byte)(raw >> 8); p[2] = (Byte)(raw >> 16);
SetUi32(p, raw);
}
}
while (++m <= 4);
}
data += 16;
curPos += 16;
fileOffset++;
}
while (++fileOffset != dataSize);
}
static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels)
{
UInt32 srcPos = 0;

View File

@@ -448,7 +448,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
// return S_FALSE;
continue; // original unRAR
}
Byte v = lens[i - 1];
Byte v = lens[(size_t)i - 1];
do
lens[i++] = v;
while (i < num);
@@ -475,7 +475,7 @@ HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
_useAlignBits = false;
// _useAlignBits = true;
for (i = 0; i < kAlignTableSize; i++)
if (lens[kMainTableSize + kDistTableSize + i] != kNumAlignBits)
if (lens[kMainTableSize + kDistTableSize + (size_t)i] != kNumAlignBits)
{
_useAlignBits = true;
break;

View File

@@ -5,10 +5,9 @@
#ifndef __COMPRESS_RAR5_DECODER_H
#define __COMPRESS_RAR5_DECODER_H
#include "../../../C/Alloc.h"
#include "../../../C/CpuArch.h"
#include "../../Common/MyBuffer.h"
#include "../../Common/MyBuffer2.h"
#include "../../Common/MyCom.h"
#include "../../Common/MyException.h"
#include "../../Common/MyVector.h"
@@ -20,35 +19,6 @@
namespace NCompress {
namespace NRar5 {
class CMidBuffer
{
Byte *_data;
size_t _size;
CLASS_NO_COPY(CMidBuffer)
public:
CMidBuffer(): _data(NULL), _size(0) {};
~CMidBuffer() { ::MidFree(_data); }
bool IsAllocated() const { return _data != NULL; }
operator Byte *() { return _data; }
operator const Byte *() const { return _data; }
size_t Size() const { return _size; }
void AllocAtLeast(size_t size)
{
if (size > _size)
{
const size_t kMinSize = (1 << 16);
if (size < kMinSize)
size = kMinSize;
::MidFree(_data);
_data = (Byte *)::MidAlloc(size);
_size = size;
}
}
};
/*
struct CInBufferException: public CSystemException

View File

@@ -1,10 +1,7 @@
// ShrinkDecoder.cpp
#include "StdAfx.h"
#include <stdio.h>
#include "../../../C/Alloc.h"
#include "../Common/InBuffer.h"
@@ -20,18 +17,19 @@ 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)
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();
if (!outBuffer.Create(kBufferSize))
return E_OUTOFMEMORY;
outBuffer.SetStream(outStream);
outBuffer.Init();
@@ -45,31 +43,69 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
_suffixes[i] = 0;
}
UInt64 prevPos = 0;
UInt64 prevPos = 0, inPrev = 0;
unsigned numBits = kNumMinBits;
unsigned head = 257;
int lastSym = -1;
Byte lastChar2 = 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 - prevPos >= (1 << 18)
|| _inProcessed - inPrev >= (1 << 20))
{
prevPos = nowPos;
inPrev = _inProcessed;
RINOK(progress->SetRatioInfo(&_inProcessed, &nowPos));
}
}
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)
return S_FALSE;
break;
numBits++;
continue;
}
if (sym != 2)
return S_FALSE;
break;
{
unsigned i;
for (i = 257; i < kNumItems; i++)
@@ -90,6 +126,14 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
}
}
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)
{
@@ -101,7 +145,8 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
{
// we need to fix the code for that case
// _parents[head] is not allowed to link to itself
return E_NOTIMPL;
res = E_NOTIMPL;
break;
}
needPrev = true;
_parents[head] = (UInt16)lastSym;
@@ -111,7 +156,7 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
}
if (_parents[sym] == kNumItems)
return S_FALSE;
break;
lastSym = sym;
unsigned cur = sym;
@@ -127,34 +172,64 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
lastChar2 = (Byte)cur;
if (needPrev)
_suffixes[head - 1] = (Byte)cur;
_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);
if (progress)
{
const UInt64 nowPos = outBuffer.GetProcessedSize();
if (nowPos - prevPos >= (1 << 18))
{
prevPos = nowPos;
const UInt64 packSize = inBuffer.GetProcessedSize();
RINOK(progress->SetRatioInfo(&packSize, &nowPos));
}
}
}
return outBuffer.Flush();
RINOK(outBuffer.Flush());
if (res == S_OK)
if (_fullStreamMode)
{
if (moreOut)
res = S_FALSE;
const UInt64 nowPos = outBuffer.GetProcessedSize();
if (outSize && *outSize != nowPos)
res = S_FALSE;
if (inSize && *inSize != _inProcessed)
res = S_FALSE;
}
return res;
}
STDMETHODIMP CDecoder ::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
{
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
catch(const CInBufferException &e) { return e.ErrorCode; }
catch(const COutBufferException &e) { return e.ErrorCode; }
// catch(const CInBufferException &e) { return e.ErrorCode; }
// catch(const COutBufferException &e) { return e.ErrorCode; }
catch(const CSystemException &e) { return e.ErrorCode; }
catch(...) { return S_FALSE; }
}
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
{
_fullStreamMode = (finishMode != 0);
return S_OK;
}
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
{
*value = _inProcessed;
return S_OK;
}
}}

View File

@@ -15,20 +15,29 @@ const unsigned kNumItems = 1 << kNumMaxBits;
class CDecoder :
public ICompressCoder,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public CMyUnknownImp
{
UInt64 _inProcessed;
bool _fullStreamMode;
UInt16 _parents[kNumItems];
Byte _suffixes[kNumItems];
Byte _stack[kNumItems];
public:
MY_UNKNOWN_IMP
HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
public:
MY_UNKNOWN_IMP2(
ICompressSetFinishMode,
ICompressGetInStreamProcessedSize)
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
};
}}

View File

@@ -49,8 +49,8 @@ HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize)
for (unsigned i = 0; i < kNumSyms / 2; i++)
{
Byte b = in[i];
levels[i * 2] = (Byte)(b & 0xF);
levels[i * 2 + 1] = (Byte)(b >> 4);
levels[(size_t)i * 2] = (Byte)(b & 0xF);
levels[(size_t)i * 2 + 1] = (Byte)(b >> 4);
}
if (!huff.BuildFull(levels))
return S_FALSE;

View File

@@ -0,0 +1,260 @@
// XzDecoder.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.h"
#include "../Common/StreamUtils.h"
#include "../Archive/IArchive.h"
#include "XzDecoder.h"
using namespace NArchive;
namespace NCompress {
namespace NXz {
void CStatInfo::Clear()
{
InSize = 0;
OutSize = 0;
PhySize = 0;
NumStreams = 0;
NumBlocks = 0;
UnpackSize_Defined = false;
NumStreams_Defined = false;
NumBlocks_Defined = false;
IsArc = false;
UnexpectedEnd = false;
DataAfterEnd = false;
Unsupported = false;
HeadersError = false;
DataError = false;
CrcError = false;
}
CXzUnpackerCPP::CXzUnpackerCPP(): InBuf(0), OutBuf(0)
{
XzUnpacker_Construct(&p, &g_Alloc);
}
CXzUnpackerCPP::~CXzUnpackerCPP()
{
XzUnpacker_Free(&p);
MidFree(InBuf);
MidFree(OutBuf);
}
HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *progress)
{
const size_t kInBufSize = (size_t)1 << 20;
const size_t kOutBufSize = (size_t)1 << 21;
Clear();
DecodeRes = SZ_OK;
XzUnpacker_Init(&xzu.p);
if (!xzu.InBuf)
{
xzu.InBuf = (Byte *)MidAlloc(kInBufSize);
if (!xzu.InBuf)
return E_OUTOFMEMORY;
}
if (!xzu.OutBuf)
{
xzu.OutBuf = (Byte *)MidAlloc(kOutBufSize);
if (!xzu.OutBuf)
return E_OUTOFMEMORY;
}
UInt32 inSize = 0;
UInt32 inPos = 0;
SizeT outPos = 0;
HRESULT readRes = S_OK;
for (;;)
{
if (inPos == inSize && readRes == S_OK)
{
inPos = inSize = 0;
readRes = seqInStream->Read(xzu.InBuf, kInBufSize, &inSize);
}
SizeT inLen = inSize - inPos;
SizeT outLen = kOutBufSize - outPos;
ECoderFinishMode finishMode = CODER_FINISH_ANY;
if (inSize == 0)
finishMode = CODER_FINISH_END;
if (outSizeLimit)
{
const UInt64 rem = *outSizeLimit - OutSize;
if (outLen >= rem)
{
outLen = (SizeT)rem;
if (finishStream)
finishMode = CODER_FINISH_END;
}
}
ECoderStatus status;
const SizeT outLenRequested = outLen;
SRes res = XzUnpacker_Code(&xzu.p,
xzu.OutBuf + outPos, &outLen,
xzu.InBuf + inPos, &inLen,
finishMode, &status);
DecodeRes = res;
inPos += (UInt32)inLen;
outPos += outLen;
InSize += inLen;
OutSize += outLen;
bool finished = ((inLen == 0 && outLen == 0) || res != SZ_OK);
if (outLen >= outLenRequested || finished)
{
if (outStream && outPos != 0)
{
RINOK(WriteStream(outStream, xzu.OutBuf, outPos));
}
outPos = 0;
}
if (progress)
{
RINOK(progress->SetRatioInfo(&InSize, &OutSize));
}
if (!finished)
continue;
{
PhySize = InSize;
NumStreams = xzu.p.numStartedStreams;
if (NumStreams > 0)
IsArc = true;
NumBlocks = xzu.p.numTotalBlocks;
UnpackSize_Defined = true;
NumStreams_Defined = true;
NumBlocks_Defined = true;
UInt64 extraSize = XzUnpacker_GetExtraSize(&xzu.p);
if (res == SZ_OK)
{
if (status == CODER_STATUS_NEEDS_MORE_INPUT)
{
extraSize = 0;
if (!XzUnpacker_IsStreamWasFinished(&xzu.p))
{
// finished at padding bytes, but padding is not aligned for 4
UnexpectedEnd = true;
res = SZ_ERROR_DATA;
}
}
else // status == CODER_STATUS_NOT_FINISHED
res = SZ_ERROR_DATA;
}
else if (res == SZ_ERROR_NO_ARCHIVE)
{
if (InSize == extraSize)
IsArc = false;
else
{
if (extraSize != 0 || inPos != inSize)
{
DataAfterEnd = true;
res = SZ_OK;
}
}
}
DecodeRes = res;
PhySize -= extraSize;
switch (res)
{
case SZ_OK: break;
case SZ_ERROR_NO_ARCHIVE: IsArc = false; break;
case SZ_ERROR_ARCHIVE: HeadersError = true; break;
case SZ_ERROR_UNSUPPORTED: Unsupported = true; break;
case SZ_ERROR_CRC: CrcError = true; break;
case SZ_ERROR_DATA: DataError = true; break;
default: DataError = true; break;
}
return readRes;
}
}
}
Int32 CDecoder::Get_Extract_OperationResult() const
{
Int32 opRes;
if (!IsArc)
opRes = NExtract::NOperationResult::kIsNotArc;
else if (UnexpectedEnd)
opRes = NExtract::NOperationResult::kUnexpectedEnd;
else if (DataAfterEnd)
opRes = NExtract::NOperationResult::kDataAfterEnd;
else if (CrcError)
opRes = NExtract::NOperationResult::kCRCError;
else if (Unsupported)
opRes = NExtract::NOperationResult::kUnsupportedMethod;
else if (HeadersError)
opRes = NExtract::NOperationResult::kDataError;
else if (DataError)
opRes = NExtract::NOperationResult::kDataError;
else if (DecodeRes != SZ_OK)
opRes = NExtract::NOperationResult::kDataError;
else
opRes = NExtract::NOperationResult::kOK;
return opRes;
}
HRESULT CComDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
{
RINOK(_decoder.Decode(inStream, outStream, outSize, _finishStream, progress));
Int32 opRes = _decoder.Get_Extract_OperationResult();
if (opRes == NArchive::NExtract::NOperationResult::kUnsupportedMethod)
return E_NOTIMPL;
if (opRes != NArchive::NExtract::NOperationResult::kOK)
return S_FALSE;
return S_OK;
}
STDMETHODIMP CComDecoder::SetFinishMode(UInt32 finishMode)
{
_finishStream = (finishMode != 0);
return S_OK;
}
STDMETHODIMP CComDecoder::GetInStreamProcessedSize(UInt64 *value)
{
*value = _decoder.InSize;
return S_OK;
}
}}

View File

@@ -0,0 +1,95 @@
// XzDecoder.h
#ifndef __XZ_DECODER_H
#define __XZ_DECODER_H
#include "../../Common/MyCom.h"
#include "../ICoder.h"
#include "../../../C/Xz.h"
// #include "../../Archive/XzHandler.h"
namespace NCompress {
namespace NXz {
struct CXzUnpackerCPP
{
Byte *InBuf;
Byte *OutBuf;
CXzUnpacker p;
CXzUnpackerCPP();
~CXzUnpackerCPP();
};
struct CStatInfo
{
UInt64 InSize;
UInt64 OutSize;
UInt64 PhySize;
UInt64 NumStreams;
UInt64 NumBlocks;
bool UnpackSize_Defined;
bool NumStreams_Defined;
bool NumBlocks_Defined;
bool IsArc;
bool UnexpectedEnd;
bool DataAfterEnd;
bool Unsupported;
bool HeadersError;
bool DataError;
bool CrcError;
CStatInfo() { Clear(); }
void Clear();
};
struct CDecoder: public CStatInfo
{
CXzUnpackerCPP xzu;
SRes DecodeRes; // it's not HRESULT
CDecoder(): DecodeRes(SZ_OK) {}
/* Decode() can return ERROR code only if there is progress or stream error.
Decode() returns S_OK in case of xz decoding error, but DecodeRes and CStatInfo contain error information */
HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *compressProgress);
Int32 Get_Extract_OperationResult() const;
};
class CComDecoder:
public ICompressCoder,
public ICompressSetFinishMode,
public ICompressGetInStreamProcessedSize,
public CMyUnknownImp
{
CDecoder _decoder;
bool _finishStream;
public:
MY_UNKNOWN_IMP2(
ICompressSetFinishMode,
ICompressGetInStreamProcessedSize)
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetFinishMode)(UInt32 finishMode);
STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
CComDecoder(): _finishStream(false) {}
};
}}
#endif

View File

@@ -0,0 +1,190 @@
// XzEncoder.cpp
#include "StdAfx.h"
#include "../../../C/Alloc.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 {
extern "C" {
static void *SzBigAlloc(ISzAllocPtr, size_t size) { return BigAlloc(size); }
static void SzBigFree(ISzAllocPtr, void *address) { BigFree(address); }
static const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
static void *SzAlloc(ISzAllocPtr, size_t size) { return MyAlloc(size); }
static void SzFree(ISzAllocPtr, void *address) { MyFree(address); }
static const ISzAlloc g_Alloc = { SzAlloc, SzFree };
}
void CEncoder::InitCoderProps()
{
Lzma2EncProps_Init(&_lzma2Props);
XzProps_Init(&xzProps);
XzFilterProps_Init(&filter);
xzProps.lzma2Props = &_lzma2Props;
// xzProps.filterProps = (_filterId != 0 ? &filter : NULL);
xzProps.filterProps = NULL;
}
CEncoder::CEncoder()
{
InitCoderProps();
}
CEncoder::~CEncoder()
{
}
HRESULT CEncoder::SetCoderProp(PROPID propID, const PROPVARIANT &prop)
{
return NLzma2::SetLzma2Prop(propID, prop, _lzma2Props);
}
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
const PROPVARIANT *coderProps, UInt32 numProps)
{
Lzma2EncProps_Init(&_lzma2Props);
for (UInt32 i = 0; i < numProps; i++)
{
RINOK(SetCoderProp(propIDs[i], coderProps[i]));
}
return S_OK;
// return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props));
}
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,
ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 * /* outSize */,
ICompressProgressInfo *progress)
{
CSeqOutStreamWrap seqOutStream;
seqOutStream.Init(outStream);
// if (IntToBool(newData))
{
/*
UInt64 size;
{
NCOM::CPropVariant prop;
RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
if (prop.vt != VT_UI8)
return E_INVALIDARG;
size = prop.uhVal.QuadPart;
RINOK(updateCallback->SetTotal(size));
}
*/
/*
CLzma2EncProps lzma2Props;
Lzma2EncProps_Init(&lzma2Props);
lzma2Props.lzmaProps.level = GetLevel();
*/
CSeqInStreamWrap seqInStream;
seqInStream.Init(inStream);
/*
{
NCOM::CPropVariant prop = (UInt64)size;
RINOK(NCompress::NLzma2::SetLzma2Prop(NCoderPropID::kReduceSize, prop, lzma2Props));
}
FOR_VECTOR (i, _methods)
{
COneMethodInfo &m = _methods[i];
SetGlobalLevelAndThreads(m
#ifndef _7ZIP_ST
, _numThreads
#endif
);
{
FOR_VECTOR (j, m.Props)
{
const CProp &prop = m.Props[j];
RINOK(NCompress::NLzma2::SetLzma2Prop(prop.Id, prop.Value, lzma2Props));
}
}
}
#ifndef _7ZIP_ST
lzma2Props.numTotalThreads = _numThreads;
#endif
*/
CCompressProgressWrap progressWrap;
progressWrap.Init(progress);
xzProps.checkId = XZ_CHECK_CRC32;
// xzProps.checkId = XZ_CHECK_CRC64;
/*
CXzProps xzProps;
CXzFilterProps filter;
XzProps_Init(&xzProps);
XzFilterProps_Init(&filter);
xzProps.lzma2Props = &_lzma2Props;
*/
/*
xzProps.filterProps = (_filterId != 0 ? &filter : NULL);
switch (_crcSize)
{
case 0: xzProps.checkId = XZ_CHECK_NO; break;
case 4: xzProps.checkId = XZ_CHECK_CRC32; break;
case 8: xzProps.checkId = XZ_CHECK_CRC64; break;
case 32: xzProps.checkId = XZ_CHECK_SHA256; break;
default: return E_INVALIDARG;
}
filter.id = _filterId;
if (_filterId == XZ_ID_Delta)
{
bool deltaDefined = false;
FOR_VECTOR (j, _filterMethod.Props)
{
const CProp &prop = _filterMethod.Props[j];
if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4)
{
UInt32 delta = (UInt32)prop.Value.ulVal;
if (delta < 1 || delta > 256)
return E_INVALIDARG;
filter.delta = delta;
deltaDefined = true;
}
}
if (!deltaDefined)
return E_INVALIDARG;
}
*/
SRes res = Xz_Encode(&seqOutStream.vt, &seqInStream.vt, &xzProps, progress ? &progressWrap.vt : NULL);
/*
if (res == SZ_OK)
return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
*/
return SResToHRESULT(res);
}
}
}}

View File

@@ -0,0 +1,44 @@
// XzEncoder.h
#ifndef __XZ_ENCODER_H
#define __XZ_ENCODER_H
#include "../../../C/XzEnc.h"
#include "../../Common/MyCom.h"
#include "../ICoder.h"
namespace NCompress {
namespace NXz {
class CEncoder:
public ICompressCoder,
public ICompressSetCoderProperties,
public CMyUnknownImp
{
// CXzEncHandle _encoder;
public:
CLzma2EncProps _lzma2Props;
CXzProps xzProps;
CXzFilterProps filter;
MY_UNKNOWN_IMP2(ICompressCoder, ICompressSetCoderProperties)
void InitCoderProps();
HRESULT SetCoderProp(PROPID propID, const PROPVARIANT &prop);
STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
CEncoder();
virtual ~CEncoder();
};
}}
#endif

View File

@@ -100,7 +100,7 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
}
}
unsigned bytePos = bitPos >> 3;
UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16);
UInt32 symbol = buf[bytePos] | ((UInt32)buf[(size_t)bytePos + 1] << 8) | ((UInt32)buf[(size_t)bytePos + 2] << 16);
symbol >>= (bitPos & 7);
symbol &= (1 << numBits) - 1;
bitPos += numBits;
@@ -129,7 +129,7 @@ HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *
_stack[i++] = (Byte)cur;
if (needPrev)
{
_suffixes[head - 1] = (Byte)cur;
_suffixes[(size_t)head - 1] = (Byte)cur;
if (symbol == head - 1)
_stack[0] = (Byte)cur;
}