rlm@1: // LzmaHandler.cpp rlm@1: rlm@1: #include "StdAfx.h" rlm@1: rlm@1: #include "LzmaHandler.h" rlm@1: rlm@1: #include "Common/Defs.h" rlm@1: #include "Common/StringConvert.h" rlm@1: #include "Common/ComTry.h" rlm@1: #include "Common/IntToString.h" rlm@1: rlm@1: #include "Windows/PropVariant.h" rlm@1: rlm@1: #include "../../Common/ProgressUtils.h" rlm@1: #include "../../Common/StreamUtils.h" rlm@1: #include "../Common/DummyOutStream.h" rlm@1: rlm@1: #include "LzmaFiltersDecode.h" rlm@1: rlm@1: namespace NArchive { rlm@1: namespace NLzma { rlm@1: rlm@1: STATPROPSTG kProps[] = rlm@1: { rlm@1: { NULL, kpidSize, VT_UI8}, rlm@1: { NULL, kpidPackSize, VT_UI8}, rlm@1: { NULL, kpidMethod, VT_UI1} rlm@1: }; rlm@1: rlm@1: IMP_IInArchive_Props rlm@1: IMP_IInArchive_ArcProps_NO rlm@1: rlm@1: STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) rlm@1: { rlm@1: *numItems = 1; rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: static void ConvertUInt32ToString(UInt32 value, wchar_t *s) rlm@1: { rlm@1: ConvertUInt64ToString(value, s + MyStringLen(s)); rlm@1: } rlm@1: rlm@1: static void DictSizeToString(UInt32 value, wchar_t *s) rlm@1: { rlm@1: for (int i = 0; i <= 31; i++) rlm@1: if ((UInt32(1) << i) == value) rlm@1: { rlm@1: ConvertUInt32ToString(i, s); rlm@1: return; rlm@1: } rlm@1: wchar_t c = L'b'; rlm@1: if ((value & ((1 << 20) - 1)) == 0) rlm@1: { rlm@1: value >>= 20; rlm@1: c = L'm'; rlm@1: } rlm@1: else if ((value & ((1 << 10) - 1)) == 0) rlm@1: { rlm@1: value >>= 10; rlm@1: c = L'k'; rlm@1: } rlm@1: ConvertUInt32ToString(value, s); rlm@1: int p = MyStringLen(s); rlm@1: s[p++] = c; rlm@1: s[p++] = L'\0'; rlm@1: } rlm@1: rlm@1: static void MyStrCat(wchar_t *d, const wchar_t *s) rlm@1: { rlm@1: MyStringCopy(d + MyStringLen(d), s); rlm@1: } rlm@1: rlm@1: STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) rlm@1: { rlm@1: if (index != 0) rlm@1: return E_INVALIDARG; rlm@1: NWindows::NCOM::CPropVariant propVariant; rlm@1: switch(propID) rlm@1: { rlm@1: case kpidSize: rlm@1: if (m_StreamInfo.HasUnpackSize()) rlm@1: propVariant = (UInt64)m_StreamInfo.UnpackSize; rlm@1: break; rlm@1: case kpidPackSize: rlm@1: propVariant = (UInt64)m_PackSize; rlm@1: break; rlm@1: case kpidMethod: rlm@1: { rlm@1: wchar_t s[64]; rlm@1: s[0] = '\0'; rlm@1: if (m_StreamInfo.IsThereFilter) rlm@1: { rlm@1: const wchar_t *f; rlm@1: if (m_StreamInfo.FilterMethod == 0) rlm@1: f = L"Copy"; rlm@1: else if (m_StreamInfo.FilterMethod == 1) rlm@1: f = L"BCJ"; rlm@1: else rlm@1: f = L"Unknown"; rlm@1: MyStrCat(s, f); rlm@1: MyStrCat(s, L" "); rlm@1: } rlm@1: MyStrCat(s, L"LZMA:"); rlm@1: DictSizeToString(m_StreamInfo.GetDicSize(), s); rlm@1: propVariant = s; rlm@1: break; rlm@1: } rlm@1: } rlm@1: propVariant.Detach(value); rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: STDMETHODIMP CHandler::Open(IInStream *inStream, rlm@1: const UInt64 * /* maxCheckStartPosition */, rlm@1: IArchiveOpenCallback * /* openArchiveCallback */) rlm@1: { rlm@1: { rlm@1: RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &m_StreamStartPosition)); rlm@1: rlm@1: HRESULT res = ReadStreamHeader(inStream, m_StreamInfo); rlm@1: if (res != S_OK) rlm@1: return S_FALSE; rlm@1: rlm@1: Byte b; rlm@1: RINOK(ReadStream_FALSE(inStream, &b, 1)); rlm@1: if (b != 0) rlm@1: return S_FALSE; rlm@1: rlm@1: UInt64 endPos; rlm@1: RINOK(inStream->Seek(0, STREAM_SEEK_END, &endPos)); rlm@1: m_PackSize = endPos - m_StreamStartPosition - m_StreamInfo.GetHeaderSize(); rlm@1: rlm@1: m_Stream = inStream; rlm@1: } rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: STDMETHODIMP CHandler::Close() rlm@1: { rlm@1: m_Stream.Release(); rlm@1: return S_OK; rlm@1: } rlm@1: rlm@1: rlm@1: STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, rlm@1: Int32 _aTestMode, IArchiveExtractCallback *extractCallback) rlm@1: { rlm@1: COM_TRY_BEGIN rlm@1: bool allFilesMode = (numItems == UInt32(-1)); rlm@1: if (!allFilesMode) rlm@1: { rlm@1: if (numItems == 0) rlm@1: return S_OK; rlm@1: if (numItems != 1) rlm@1: return E_INVALIDARG; rlm@1: if (indices[0] != 0) rlm@1: return E_INVALIDARG; rlm@1: } rlm@1: rlm@1: bool testMode = (_aTestMode != 0); rlm@1: rlm@1: RINOK(extractCallback->SetTotal(m_PackSize)); rlm@1: rlm@1: UInt64 currentTotalPacked = 0; rlm@1: rlm@1: CDummyOutStream *outStreamSpec = new CDummyOutStream; rlm@1: CMyComPtr outStream(outStreamSpec); rlm@1: rlm@1: { rlm@1: CMyComPtr realOutStream; rlm@1: Int32 askMode = testMode ? rlm@1: NArchive::NExtract::NAskMode::kTest : rlm@1: NArchive::NExtract::NAskMode::kExtract; rlm@1: rlm@1: RINOK(extractCallback->GetStream(0, &realOutStream, askMode)); rlm@1: rlm@1: outStreamSpec->SetStream(realOutStream); rlm@1: outStreamSpec->Init(); rlm@1: if(!testMode && !realOutStream) rlm@1: return S_OK; rlm@1: extractCallback->PrepareOperation(askMode); rlm@1: } rlm@1: rlm@1: CLocalProgress *lps = new CLocalProgress; rlm@1: CMyComPtr progress = lps; rlm@1: lps->Init(extractCallback, true); rlm@1: rlm@1: CDecoder decoder; rlm@1: RINOK(m_Stream->Seek(m_StreamStartPosition, STREAM_SEEK_SET, NULL)); rlm@1: UInt64 streamPos = m_StreamStartPosition; rlm@1: Int32 opRes = NArchive::NExtract::NOperationResult::kOK; rlm@1: bool firstItem = true; rlm@1: for (;;) rlm@1: { rlm@1: CHeader st; rlm@1: HRESULT result = ReadStreamHeader(m_Stream, st); rlm@1: if (result != S_OK) rlm@1: { rlm@1: if (firstItem) rlm@1: return E_FAIL; rlm@1: break; rlm@1: } rlm@1: firstItem = false; rlm@1: rlm@1: lps->OutSize = outStreamSpec->GetSize(); rlm@1: lps->InSize = currentTotalPacked; rlm@1: RINOK(lps->SetCur()); rlm@1: rlm@1: streamPos += st.GetHeaderSize(); rlm@1: UInt64 packProcessed; rlm@1: rlm@1: { rlm@1: result = decoder.Code( rlm@1: EXTERNAL_CODECS_VARS rlm@1: st, m_Stream, outStream, &packProcessed, progress); rlm@1: if (result == E_NOTIMPL) rlm@1: { rlm@1: opRes = NArchive::NExtract::NOperationResult::kUnSupportedMethod; rlm@1: break; rlm@1: } rlm@1: if (result == S_FALSE) rlm@1: { rlm@1: opRes = NArchive::NExtract::NOperationResult::kDataError; rlm@1: break; rlm@1: } rlm@1: RINOK(result); rlm@1: } rlm@1: rlm@1: if (packProcessed == (UInt64)(Int64)-1) rlm@1: break; rlm@1: RINOK(m_Stream->Seek(streamPos + packProcessed, STREAM_SEEK_SET, NULL)); rlm@1: currentTotalPacked += packProcessed; rlm@1: streamPos += packProcessed; rlm@1: } rlm@1: outStream.Release(); rlm@1: return extractCallback->SetOperationResult(opRes); rlm@1: COM_TRY_END rlm@1: } rlm@1: rlm@1: IMPL_ISetCompressCodecsInfo rlm@1: rlm@1: }}