mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 15:14:59 -06:00
183 lines
3.9 KiB
C++
Executable File
183 lines
3.9 KiB
C++
Executable File
// PpmdDecoder.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "Common/Defs.h"
|
|
#include "Windows/Defs.h"
|
|
|
|
#include "PpmdDecoder.h"
|
|
|
|
namespace NCompress {
|
|
namespace NPpmd {
|
|
|
|
const int kLenIdFinished = -1;
|
|
const int kLenIdNeedInit = -2;
|
|
|
|
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *properties, UInt32 size)
|
|
{
|
|
if (size < 5)
|
|
return E_INVALIDARG;
|
|
_order = properties[0];
|
|
_usedMemorySize = 0;
|
|
for (int i = 0; i < 4; i++)
|
|
_usedMemorySize += ((UInt32)(properties[1 + i])) << (i * 8);
|
|
|
|
if (_usedMemorySize > kMaxMemBlockSize)
|
|
return E_NOTIMPL;
|
|
|
|
if (!_rangeDecoder.Create(1 << 20))
|
|
return E_OUTOFMEMORY;
|
|
if (!_info.SubAllocator.StartSubAllocator(_usedMemorySize))
|
|
return E_OUTOFMEMORY;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
class CDecoderFlusher
|
|
{
|
|
CDecoder *_coder;
|
|
public:
|
|
bool NeedFlush;
|
|
CDecoderFlusher(CDecoder *coder): _coder(coder), NeedFlush(true) {}
|
|
~CDecoderFlusher()
|
|
{
|
|
if (NeedFlush)
|
|
_coder->Flush();
|
|
_coder->ReleaseStreams();
|
|
}
|
|
};
|
|
|
|
HRESULT CDecoder::CodeSpec(UInt32 size, Byte *memStream)
|
|
{
|
|
if (_outSizeDefined)
|
|
{
|
|
const UInt64 rem = _outSize - _processedSize;
|
|
if (size > rem)
|
|
size = (UInt32)rem;
|
|
}
|
|
const UInt32 startSize = size;
|
|
|
|
if (_remainLen == kLenIdFinished)
|
|
return S_OK;
|
|
if (_remainLen == kLenIdNeedInit)
|
|
{
|
|
_rangeDecoder.Init();
|
|
_remainLen = 0;
|
|
_info.MaxOrder = 0;
|
|
_info.StartModelRare(_order);
|
|
}
|
|
while (size != 0)
|
|
{
|
|
int symbol = _info.DecodeSymbol(&_rangeDecoder);
|
|
if (symbol < 0)
|
|
{
|
|
_remainLen = kLenIdFinished;
|
|
break;
|
|
}
|
|
if (memStream != 0)
|
|
*memStream++ = (Byte)symbol;
|
|
else
|
|
_outStream.WriteByte((Byte)symbol);
|
|
size--;
|
|
}
|
|
_processedSize += startSize - size;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
|
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
|
|
{
|
|
if (!_outStream.Create(1 << 20))
|
|
return E_OUTOFMEMORY;
|
|
|
|
SetInStream(inStream);
|
|
_outStream.SetStream(outStream);
|
|
SetOutStreamSize(outSize);
|
|
CDecoderFlusher flusher(this);
|
|
|
|
for (;;)
|
|
{
|
|
_processedSize = _outStream.GetProcessedSize();
|
|
UInt32 curSize = (1 << 18);
|
|
RINOK(CodeSpec(curSize, NULL));
|
|
if (_remainLen == kLenIdFinished)
|
|
break;
|
|
if (progress != NULL)
|
|
{
|
|
UInt64 inSize = _rangeDecoder.GetProcessedSize();
|
|
RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
|
|
}
|
|
if (_outSizeDefined)
|
|
if (_outStream.GetProcessedSize() >= _outSize)
|
|
break;
|
|
}
|
|
flusher.NeedFlush = false;
|
|
return Flush();
|
|
}
|
|
|
|
#ifdef _NO_EXCEPTIONS
|
|
|
|
#define PPMD_TRY_BEGIN
|
|
#define PPMD_TRY_END
|
|
|
|
#else
|
|
|
|
#define PPMD_TRY_BEGIN try {
|
|
#define PPMD_TRY_END } \
|
|
catch(const CInBufferException &e) { return e.ErrorCode; } \
|
|
catch(const COutBufferException &e) { return e.ErrorCode; } \
|
|
catch(...) { return S_FALSE; }
|
|
|
|
#endif
|
|
|
|
|
|
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
|
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
|
{
|
|
PPMD_TRY_BEGIN
|
|
return CodeReal(inStream, outStream, inSize, outSize, progress);
|
|
PPMD_TRY_END
|
|
}
|
|
|
|
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
|
|
{
|
|
_rangeDecoder.SetStream(inStream);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDecoder::ReleaseInStream()
|
|
{
|
|
_rangeDecoder.ReleaseStream();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
|
{
|
|
_outSizeDefined = (outSize != NULL);
|
|
if (_outSizeDefined)
|
|
_outSize = *outSize;
|
|
_processedSize = 0;
|
|
_remainLen = kLenIdNeedInit;
|
|
_outStream.Init();
|
|
return S_OK;
|
|
}
|
|
|
|
#ifndef NO_READ_FROM_CODER
|
|
|
|
STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
|
|
{
|
|
PPMD_TRY_BEGIN
|
|
if (processedSize)
|
|
*processedSize = 0;
|
|
const UInt64 startPos = _processedSize;
|
|
RINOK(CodeSpec(size, (Byte *)data));
|
|
if (processedSize)
|
|
*processedSize = (UInt32)(_processedSize - startPos);
|
|
return Flush();
|
|
PPMD_TRY_END
|
|
}
|
|
|
|
#endif
|
|
|
|
}}
|