diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp | 348 |
1 files changed, 261 insertions, 87 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp b/src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp index a83e6a1ad..279cdefb7 100644 --- a/src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp +++ b/src/libs/7zip/win/CPP/7zip/Archive/LzmaHandler.cpp @@ -4,10 +4,10 @@ #include "../../../C/CpuArch.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" +#include "../../Common/ComTry.h" +#include "../../Common/IntToString.h" -#include "Windows/PropVariant.h" +#include "../../Windows/PropVariant.h" #include "../Common/CreateCoder.h" #include "../Common/ProgressUtils.h" @@ -26,17 +26,24 @@ namespace NLzma { static bool CheckDicSize(const Byte *p) { UInt32 dicSize = GetUi32(p); - for (int i = 1; i <= 30; i++) + if (dicSize == 1) + return true; + for (unsigned i = 0; i <= 30; i++) if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i)) return true; return (dicSize == 0xFFFFFFFF); } -STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidSize, VT_UI8}, - { NULL, kpidPackSize, VT_UI8}, - { NULL, kpidMethod, VT_BSTR} + kpidSize, + kpidPackSize, + kpidMethod +}; + +static const Byte kArcProps[] = +{ + kpidNumStreams }; struct CHeader @@ -62,16 +69,17 @@ bool CHeader::Parse(const Byte *buf, bool isThereFilter) return LzmaProps[0] < 5 * 5 * 9 && FilterID < 2 && - (!HasSize() || Size < ((UInt64)1 << 56)) && - CheckDicSize(LzmaProps + 1); + (!HasSize() || Size < ((UInt64)1 << 56)) + && CheckDicSize(LzmaProps + 1); } class CDecoder { - NCompress::NLzma::CDecoder *_lzmaDecoderSpec; CMyComPtr<ICompressCoder> _lzmaDecoder; CMyComPtr<ISequentialOutStream> _bcjStream; public: + NCompress::NLzma::CDecoder *_lzmaDecoderSpec; + ~CDecoder(); HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS bool filtered, ISequentialInStream *inStream); @@ -86,8 +94,8 @@ public: { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); } }; -static const UInt64 k_BCJ = 0x03030103; - +static const UInt32 k_BCJ = 0x03030103; + HRESULT CDecoder::Create( DECL_EXTERNAL_CODECS_LOC_VARS bool filteredMode, ISequentialInStream *inStream) @@ -95,6 +103,7 @@ HRESULT CDecoder::Create( if (!_lzmaDecoder) { _lzmaDecoderSpec = new NCompress::NLzma::CDecoder; + _lzmaDecoderSpec->FinishStream = true; _lzmaDecoder = _lzmaDecoderSpec; } @@ -166,6 +175,10 @@ HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream, } RINOK(res); + if (header.HasSize()) + if (_lzmaDecoderSpec->GetOutputProcessedSize() != header.Size) + return S_FALSE; + return S_OK; } @@ -178,12 +191,25 @@ class CHandler: { CHeader _header; bool _lzma86; - UInt64 _startPosition; - UInt64 _packSize; - bool _packSizeDefined; CMyComPtr<IInStream> _stream; CMyComPtr<ISequentialInStream> _seqStream; + bool _isArc; + bool _needSeekToStart; + bool _dataAfterEnd; + bool _needMoreInput; + + bool _packSize_Defined; + bool _unpackSize_Defined; + bool _numStreams_Defined; + + bool _unsupported; + bool _dataError; + + UInt64 _packSize; + UInt64 _unpackSize; + UInt64 _numStreams; + DECL_EXTERNAL_CODECS_VARS DECL_ISetCompressCodecsInfo @@ -204,14 +230,26 @@ public: }; IMP_IInArchive_Props -IMP_IInArchive_ArcProps_NO_Table +IMP_IInArchive_ArcProps STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { - case kpidPhySize: if (_packSizeDefined) prop = _packSize; break; + case kpidPhySize: if (_packSize_Defined) prop = _packSize; break; + case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break; + case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break; + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;; + if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd; + if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd; + if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod; + if (_dataError) v |= kpv_ErrorFlags_DataError; + prop = v; + } } prop.Detach(value); return S_OK; @@ -226,50 +264,37 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) static void DictSizeToString(UInt32 value, char *s) { for (int i = 0; i <= 31; i++) - if ((UInt32(1) << i) == value) + if (((UInt32)1 << i) == value) { ::ConvertUInt32ToString(i, s); return; } char c = 'b'; - if ((value & ((1 << 20) - 1)) == 0) - { - value >>= 20; - c = 'm'; - } - else if ((value & ((1 << 10) - 1)) == 0) - { - value >>= 10; - c = 'k'; - } + if ((value & ((1 << 20) - 1)) == 0) { value >>= 20; c = 'm'; } + else if ((value & ((1 << 10) - 1)) == 0) { value >>= 10; c = 'k'; } ::ConvertUInt32ToString(value, s); - int p = MyStringLen(s); - s[p++] = c; - s[p++] = '\0'; -} - -static void MyStrCat(char *d, const char *s) -{ - MyStringCopy(d + MyStringLen(d), s); + s += MyStringLen(s); + *s++ = c; + *s = 0; } -STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value) { NCOM::CPropVariant prop; - switch(propID) + switch (propID) { case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break; - case kpidPackSize: if (_packSizeDefined) prop = _packSize; break; + case kpidPackSize: if (_packSize_Defined) prop = _packSize; break; case kpidMethod: if (_stream) { - char s[64]; - s[0] = '\0'; + char sz[64]; + char *s = sz; if (_header.FilterID != 0) - MyStrCat(s, "BCJ "); - MyStrCat(s, "LZMA:"); - DictSizeToString(_header.GetDicSize(), s + MyStringLen(s)); - prop = s; + s = MyStpCpy(s, "BCJ "); + s = MyStpCpy(s, "LZMA:"); + DictSizeToString(_header.GetDicSize(), s); + prop = sz; } break; } @@ -277,46 +302,126 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIA return S_OK; } +API_FUNC_static_IsArc IsArc_Lzma(const Byte *p, size_t size) +{ + const UInt32 kHeaderSize = 1 + 4 + 8; + if (size < kHeaderSize) + return k_IsArc_Res_NEED_MORE; + if (p[0] >= 5 * 5 * 9) + return k_IsArc_Res_NO; + UInt64 unpackSize = GetUi64(p + 1 + 4); + if (unpackSize != (UInt64)(Int64)-1) + { + if (size >= ((UInt64)1 << 56)) + return k_IsArc_Res_NO; + } + if (unpackSize != 0) + { + if (size < kHeaderSize + 2) + return k_IsArc_Res_NEED_MORE; + if (p[kHeaderSize] != 0) + return k_IsArc_Res_NO; + if (unpackSize != (UInt64)(Int64)-1) + { + if ((p[kHeaderSize + 1] & 0x80) != 0) + return k_IsArc_Res_NO; + } + } + if (!CheckDicSize(p + 1)) + // return k_IsArc_Res_YES_LOW_PROB; + return k_IsArc_Res_NO; + return k_IsArc_Res_YES; +} +} + +API_FUNC_static_IsArc IsArc_Lzma86(const Byte *p, size_t size) +{ + if (size < 1) + return k_IsArc_Res_NEED_MORE; + Byte filterID = p[0]; + if (filterID != 0 && filterID != 1) + return k_IsArc_Res_NO; + return IsArc_Lzma(p + 1, size - 1); +} +} + STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *) { - RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &_startPosition)); - - const UInt32 kBufSize = 1 + 5 + 8 + 1; + Close(); + + const UInt32 kBufSize = 1 + 5 + 8 + 2; Byte buf[kBufSize]; - + RINOK(ReadStream_FALSE(inStream, buf, kBufSize)); - + if (!_header.Parse(buf, _lzma86)) return S_FALSE; const Byte *start = buf + GetHeaderSize(); - if (start[0] != 0) + if (start[0] != 0 /* || (start[1] & 0x80) != 0 */ ) // empty stream with EOS is not 0x80 + return S_FALSE; + + RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize)); + if (_packSize >= 24 && _header.Size == 0 && _header.FilterID == 0 && _header.LzmaProps[0] == 0) return S_FALSE; - - UInt64 endPos; - RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); - _packSize = endPos - _startPosition; - _packSizeDefined = true; - + _isArc = true; _stream = inStream; _seqStream = inStream; + _needSeekToStart = true; return S_OK; } STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream) { Close(); + _isArc = true; _seqStream = stream; return S_OK; } STDMETHODIMP CHandler::Close() { - _packSizeDefined = false; + _isArc = false; + _packSize_Defined = false; + _unpackSize_Defined = false; + _numStreams_Defined = false; + + _dataAfterEnd = false; + _needMoreInput = false; + _unsupported = false; + _dataError = false; + + _packSize = 0; + + _needSeekToStart = false; + _stream.Release(); _seqStream.Release(); return S_OK; } +class CCompressProgressInfoImp: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr<IArchiveOpenCallback> Callback; +public: + UInt64 Offset; + + MY_UNKNOWN_IMP1(ICompressProgressInfo) + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + void Init(IArchiveOpenCallback *callback) { Callback = callback; } +}; + +STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) +{ + if (Callback) + { + UInt64 files = 0; + UInt64 value = Offset + *inSize; + return Callback->SetCompleted(&files, &value); + } + return S_OK; +} STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) @@ -324,13 +429,13 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, COM_TRY_BEGIN if (numItems == 0) return S_OK; - if (numItems != (UInt32)-1 && (numItems != 1 || indices[0] != 0)) + if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0)) return E_INVALIDARG; - if (_stream) + if (_packSize_Defined) extractCallback->SetTotal(_packSize); - - + + CMyComPtr<ISequentialOutStream> realOutStream; Int32 askMode = testMode ? NExtract::NAskMode::kTest : @@ -338,7 +443,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); if (!testMode && !realOutStream) return S_OK; - + extractCallback->PrepareOperation(askMode); CDummyOutStream *outStreamSpec = new CDummyOutStream; @@ -351,78 +456,147 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressProgressInfo> progress = lps; lps->Init(extractCallback, true); - if (_stream) + if (_needSeekToStart) { - RINOK(_stream->Seek(_startPosition, STREAM_SEEK_SET, NULL)); + if (!_stream) + return E_FAIL; + RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL)); } + else + _needSeekToStart = true; CDecoder decoder; HRESULT result = decoder.Create( EXTERNAL_CODECS_VARS _lzma86, _seqStream); RINOK(result); - - Int32 opRes = NExtract::NOperationResult::kOK; + bool firstItem = true; + UInt64 packSize = 0; + UInt64 unpackSize = 0; + UInt64 numStreams = 0; + + bool dataAfterEnd = false; + for (;;) { - lps->OutSize = outStreamSpec->GetSize(); - lps->InSize = _packSize = decoder.GetInputProcessedSize(); - _packSizeDefined = true; + lps->InSize = packSize; + lps->OutSize = unpackSize; RINOK(lps->SetCur()); - CHeader st; - const UInt32 kBufSize = 1 + 5 + 8; Byte buf[kBufSize]; const UInt32 headerSize = GetHeaderSize(); UInt32 processed; RINOK(decoder.ReadInput(buf, headerSize, &processed)); if (processed != headerSize) + { + if (processed != 0) + dataAfterEnd = true; break; - + } + + CHeader st; if (!st.Parse(buf, _lzma86)) + { + dataAfterEnd = true; break; + } + numStreams++; firstItem = false; result = decoder.Code(st, outStream, progress); + + packSize = decoder.GetInputProcessedSize(); + unpackSize = outStreamSpec->GetSize(); + if (result == E_NOTIMPL) { - opRes = NExtract::NOperationResult::kUnSupportedMethod; + _unsupported = true; + result = S_FALSE; break; } if (result == S_FALSE) - { - opRes = NExtract::NOperationResult::kDataError; break; - } RINOK(result); } + if (firstItem) - return E_FAIL; + { + _isArc = false; + result = S_FALSE; + } + else if (result == S_OK || result == S_FALSE) + { + if (dataAfterEnd) + _dataAfterEnd = true; + else if (decoder._lzmaDecoderSpec->NeedMoreInput) + _needMoreInput = true; + + _packSize = packSize; + _unpackSize = unpackSize; + _numStreams = numStreams; + + _packSize_Defined = true; + _unpackSize_Defined = true; + _numStreams_Defined = true; + } + + Int32 opResult = NExtract::NOperationResult::kOK; + + if (!_isArc) + opResult = NExtract::NOperationResult::kIsNotArc; + else if (_needMoreInput) + opResult = NExtract::NOperationResult::kUnexpectedEnd; + else if (_unsupported) + opResult = NExtract::NOperationResult::kUnsupportedMethod; + else if (_dataAfterEnd) + opResult = NExtract::NOperationResult::kDataAfterEnd; + else if (result == S_FALSE) + opResult = NExtract::NOperationResult::kDataError; + else if (result == S_OK) + opResult = NExtract::NOperationResult::kOK; + else + return result; + outStream.Release(); - return extractCallback->SetOperationResult(opRes); + return extractCallback->SetOperationResult(opResult); COM_TRY_END } IMPL_ISetCompressCodecsInfo -static IInArchive *CreateArc() { return new CHandler(false); } -static IInArchive *CreateArc86() { return new CHandler(true); } - namespace NLzmaAr { - + +IMP_CreateArcIn_2(CHandler(false)) + static CArcInfo g_ArcInfo = - { L"lzma", L"lzma", 0, 0xA, { 0 }, 0, true, CreateArc, NULL }; + { "lzma", "lzma", 0, 0xA, + 0, { 0 }, + // 2, { 0x5D, 0x00 }, + 0, + NArcInfoFlags::kStartOpen | + NArcInfoFlags::kKeepName, + CreateArc, NULL, + IsArc_Lzma }; + REGISTER_ARC(Lzma) } namespace NLzma86Ar { +IMP_CreateArcIn_2(CHandler(true)) + static CArcInfo g_ArcInfo = - { L"lzma86", L"lzma86", 0, 0xB, { 0 }, 0, true, CreateArc86, NULL }; + { "lzma86", "lzma86", 0, 0xB, + 0, { 0 }, + 0, + NArcInfoFlags::kKeepName, + CreateArc, NULL, + IsArc_Lzma86 }; + REGISTER_ARC(Lzma86) } |