Source code
Revision control
Copy as Markdown
Other Tools
// LzmaDecoder.cpp↩
↩
#include "StdAfx.h"↩
↩
#include "../../../C/Alloc.h"↩
↩
#include "../Common/StreamUtils.h"↩
↩
#include "LzmaDecoder.h"↩
↩
static HRESULT SResToHRESULT(SRes res)↩
{↩
switch (res)↩
{↩
case SZ_OK: return S_OK;↩
case SZ_ERROR_MEM: return E_OUTOFMEMORY;↩
case SZ_ERROR_PARAM: return E_INVALIDARG;↩
case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;↩
case SZ_ERROR_DATA: return S_FALSE;↩
}↩
return E_FAIL;↩
}↩
↩
namespace NCompress {↩
namespace NLzma {↩
↩
CDecoder::CDecoder():↩
_inBuf(NULL),↩
_lzmaStatus(LZMA_STATUS_NOT_SPECIFIED),↩
FinishStream(false),↩
_propsWereSet(false),↩
_outSizeDefined(false),↩
_outStep(1 << 20),↩
_inBufSize(0),↩
_inBufSizeNew(1 << 20)↩
{↩
_inProcessed = 0;↩
_inPos = _inLim = 0;↩
↩
/*↩
AlignOffsetAlloc_CreateVTable(&_alloc);↩
_alloc.numAlignBits = 7;↩
_alloc.offset = 0;↩
*/↩
LzmaDec_Construct(&_state);↩
}↩
↩
CDecoder::~CDecoder()↩
{↩
LzmaDec_Free(&_state, &g_AlignedAlloc); // &_alloc.vt↩
MyFree(_inBuf);↩
}↩
↩
STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; }↩
STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }↩
↩
HRESULT CDecoder::CreateInputBuffer()↩
{↩
if (!_inBuf || _inBufSizeNew != _inBufSize)↩
{↩
MyFree(_inBuf);↩
_inBufSize = 0;↩
_inBuf = (Byte *)MyAlloc(_inBufSizeNew);↩
if (!_inBuf)↩
return E_OUTOFMEMORY;↩
_inBufSize = _inBufSizeNew;↩
}↩
return S_OK;↩
}↩
↩
↩
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)↩
{↩
RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_AlignedAlloc))) // &_alloc.vt↩
_propsWereSet = true;↩
return CreateInputBuffer();↩
}↩
↩
↩
void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)↩
{↩
_outSizeDefined = (outSize != NULL);↩
_outSize = 0;↩
if (_outSizeDefined)↩
_outSize = *outSize;↩
_outProcessed = 0;↩
_lzmaStatus = LZMA_STATUS_NOT_SPECIFIED;↩
↩
LzmaDec_Init(&_state);↩
}↩
↩
↩
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)↩
{↩
_inProcessed = 0;↩
_inPos = _inLim = 0;↩
SetOutStreamSizeResume(outSize);↩
return S_OK;↩
}↩
↩
↩
STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)↩
{↩
FinishStream = (finishMode != 0);↩
return S_OK;↩
}↩
↩
↩
STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)↩
{↩
*value = _inProcessed;↩
return S_OK;↩
}↩
↩
↩
HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)↩
{↩
if (!_inBuf || !_propsWereSet)↩
return S_FALSE;↩
↩
const UInt64 startInProgress = _inProcessed;↩
SizeT wrPos = _state.dicPos;↩
HRESULT readRes = S_OK;↩
↩
for (;;)↩
{↩
if (_inPos == _inLim && readRes == S_OK)↩
{↩
_inPos = _inLim = 0;↩
readRes = inStream->Read(_inBuf, _inBufSize, &_inLim);↩
}↩
↩
const SizeT dicPos = _state.dicPos;↩
SizeT size;↩
{↩
SizeT next = _state.dicBufSize;↩
if (next - wrPos > _outStep)↩
next = wrPos + _outStep;↩
size = next - dicPos;↩
}↩
↩
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;↩
if (_outSizeDefined)↩
{↩
const UInt64 rem = _outSize - _outProcessed;↩
if (size >= rem)↩
{↩
size = (SizeT)rem;↩
if (FinishStream)↩
finishMode = LZMA_FINISH_END;↩
}↩
}↩
↩
SizeT inProcessed = _inLim - _inPos;↩
ELzmaStatus status;↩
↩
SRes res = LzmaDec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status);↩
↩
_lzmaStatus = status;↩
_inPos += (UInt32)inProcessed;↩
_inProcessed += inProcessed;↩
const SizeT outProcessed = _state.dicPos - dicPos;↩
_outProcessed += outProcessed;↩
↩
// we check for LZMA_STATUS_NEEDS_MORE_INPUT to allow RangeCoder initialization, if (_outSizeDefined && _outSize == 0)↩
bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);↩
↩
bool needStop = (res != 0↩
|| (inProcessed == 0 && outProcessed == 0)↩
|| status == LZMA_STATUS_FINISHED_WITH_MARK↩
|| (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT));↩
↩
if (needStop || outProcessed >= size)↩
{↩
HRESULT res2 = WriteStream(outStream, _state.dic + wrPos, _state.dicPos - wrPos);↩
↩
if (_state.dicPos == _state.dicBufSize)↩
_state.dicPos = 0;↩
wrPos = _state.dicPos;↩
↩
RINOK(res2);↩
↩
if (needStop)↩
{↩
if (res != 0)↩
return S_FALSE;↩
↩
if (status == LZMA_STATUS_FINISHED_WITH_MARK)↩
{↩
if (FinishStream)↩
if (_outSizeDefined && _outSize != _outProcessed)↩
return S_FALSE;↩
return readRes;↩
}↩
↩
if (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT)↩
if (!FinishStream || status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)↩
return readRes;↩
↩
return S_FALSE;↩
}↩
}↩
↩
if (progress)↩
{↩
const UInt64 inSize = _inProcessed - startInProgress;↩
RINOK(progress->SetRatioInfo(&inSize, &_outProcessed));↩
}↩
}↩
}↩
↩
↩
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,↩
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)↩
{↩
if (!_inBuf)↩
return E_INVALIDARG;↩
SetOutStreamSize(outSize);↩
HRESULT res = CodeSpec(inStream, outStream, progress);↩
if (res == S_OK)↩
if (FinishStream && inSize && *inSize != _inProcessed)↩
res = S_FALSE;↩
return res;↩
}↩
↩
↩
#ifndef NO_READ_FROM_CODER↩
↩
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }↩
STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }↩
↩
↩
STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)↩
{↩
if (processedSize)↩
*processedSize = 0;↩
↩
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;↩
if (_outSizeDefined)↩
{↩
const UInt64 rem = _outSize - _outProcessed;↩
if (size >= rem)↩
{↩
size = (UInt32)rem;↩
if (FinishStream)↩
finishMode = LZMA_FINISH_END;↩
}↩
}↩
↩
HRESULT readRes = S_OK;↩
↩
for (;;)↩
{↩
if (_inPos == _inLim && readRes == S_OK)↩
{↩
_inPos = _inLim = 0;↩
readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);↩
}↩
↩
SizeT inProcessed = _inLim - _inPos;↩
SizeT outProcessed = size;↩
ELzmaStatus status;↩
↩
SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,↩
_inBuf + _inPos, &inProcessed, finishMode, &status);↩
↩
_lzmaStatus = status;↩
_inPos += (UInt32)inProcessed;↩
_inProcessed += inProcessed;↩
_outProcessed += outProcessed;↩
size -= (UInt32)outProcessed;↩
data = (Byte *)data + outProcessed;↩
if (processedSize)↩
*processedSize += (UInt32)outProcessed;↩
↩
if (res != 0)↩
return S_FALSE;↩
↩
/*↩
if (status == LZMA_STATUS_FINISHED_WITH_MARK)↩
return readRes;↩
↩
if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)↩
{↩
if (FinishStream↩
&& _outSizeDefined && _outProcessed >= _outSize↩
&& status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)↩
return S_FALSE;↩
return readRes;↩
}↩
*/↩
↩
if (inProcessed == 0 && outProcessed == 0)↩
return readRes;↩
}↩
}↩
↩
↩
HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)↩
{↩
SetOutStreamSizeResume(outSize);↩
return CodeSpec(_inStream, outStream, progress);↩
}↩
↩
↩
HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize)↩
{↩
RINOK(CreateInputBuffer());↩
↩
if (processedSize)↩
*processedSize = 0;↩
↩
HRESULT readRes = S_OK;↩
↩
while (size != 0)↩
{↩
if (_inPos == _inLim)↩
{↩
_inPos = _inLim = 0;↩
if (readRes == S_OK)↩
readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);↩
if (_inLim == 0)↩
break;↩
}↩
↩
UInt32 cur = _inLim - _inPos;↩
if (cur > size)↩
cur = size;↩
memcpy(data, _inBuf + _inPos, cur);↩
_inPos += cur;↩
_inProcessed += cur;↩
size -= cur;↩
data = (Byte *)data + cur;↩
if (processedSize)↩
*processedSize += cur;↩
}↩
↩
return readRes;↩
}↩
↩
#endif↩
↩
}}↩