summaryrefslogtreecommitdiffstats
path: root/other-licenses/7zstub/src/CPP/7zip/Compress/LzmaDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'other-licenses/7zstub/src/CPP/7zip/Compress/LzmaDecoder.cpp')
-rw-r--r--other-licenses/7zstub/src/CPP/7zip/Compress/LzmaDecoder.cpp343
1 files changed, 343 insertions, 0 deletions
diff --git a/other-licenses/7zstub/src/CPP/7zip/Compress/LzmaDecoder.cpp b/other-licenses/7zstub/src/CPP/7zip/Compress/LzmaDecoder.cpp
new file mode 100644
index 000000000..b6a8d3fbd
--- /dev/null
+++ b/other-licenses/7zstub/src/CPP/7zip/Compress/LzmaDecoder.cpp
@@ -0,0 +1,343 @@
+// 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
+
+}}