From 2efa10565ac395d2ce9a679ead46e70fb2f963eb Mon Sep 17 00:00:00 2001 From: Igor Pavlov Date: Sun, 30 Apr 2017 00:00:00 +0000 Subject: 17.00 --- CPP/7zip/Compress/XzDecoder.cpp | 260 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 CPP/7zip/Compress/XzDecoder.cpp (limited to 'CPP/7zip/Compress/XzDecoder.cpp') diff --git a/CPP/7zip/Compress/XzDecoder.cpp b/CPP/7zip/Compress/XzDecoder.cpp new file mode 100644 index 00000000..e7ee6046 --- /dev/null +++ b/CPP/7zip/Compress/XzDecoder.cpp @@ -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; +} + +}} -- cgit v1.2.3