Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Compress/XzDecoder.cpp')
-rw-r--r--CPP/7zip/Compress/XzDecoder.cpp260
1 files changed, 260 insertions, 0 deletions
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;
+}
+
+}}