diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2015-09-22 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:55 +0300 |
commit | f6444c32568553e0261ca0105083658f12be6284 (patch) | |
tree | 8f4eb80f6accd2a9d0759e2564fd6a2b00836e02 /CPP/7zip/Archive/Cab | |
parent | cba375916fb18db8b9101aedf4fa079e019311b3 (diff) |
15.0715.07
Diffstat (limited to 'CPP/7zip/Archive/Cab')
-rw-r--r-- | CPP/7zip/Archive/Cab/CabBlockInStream.cpp | 11 | ||||
-rw-r--r-- | CPP/7zip/Archive/Cab/CabBlockInStream.h | 6 | ||||
-rw-r--r-- | CPP/7zip/Archive/Cab/CabHandler.cpp | 125 |
3 files changed, 119 insertions, 23 deletions
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp index 625276f3..c193434f 100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp @@ -29,15 +29,24 @@ CCabBlockInStream::~CCabBlockInStream() static UInt32 CheckSum(const Byte *p, UInt32 size) { UInt32 sum = 0; - for (UInt32 i = size >> 2; i != 0; i--) + + for (; size >= 8; size -= 8) + { + sum ^= GetUi32(p) ^ GetUi32(p + 4); + p += 8; + } + + if (size >= 4) { sum ^= GetUi32(p); p += 4; } + size &= 3; if (size > 2) sum ^= (UInt32)(*p++) << 16; if (size > 1) sum ^= (UInt32)(*p++) << 8; if (size > 0) sum ^= (UInt32)(*p++); + return sum; } diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.h b/CPP/7zip/Archive/Cab/CabBlockInStream.h index b795ed97..af89abb6 100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.h +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h @@ -25,10 +25,16 @@ public: CCabBlockInStream(): _buf(0), ReservedSize(0), MsZip(false) {} ~CCabBlockInStream(); + bool Create(); + void InitForNewBlock() { _size = 0; _pos = 0; } + HRESULT PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize); + UInt32 GetPackSizeAvail() const { return _size - _pos; } + const Byte *GetData() const { return _buf + _pos; } + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); }; diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index 4235ec34..711bfdf7 100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -569,13 +569,14 @@ public: UInt64 folderSize, IArchiveExtractCallback *extractCallback, bool testMode); - HRESULT FlushCorrupted(); + HRESULT FlushCorrupted(unsigned folderIndex); HRESULT Unsupported(); UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; } UInt64 GetPosInFolder() const { return m_PosInFolder; } }; + void CFolderOutStream::Init( const CMvDatabaseEx *database, const CRecordVector<bool> *extractStatuses, @@ -600,6 +601,7 @@ void CFolderOutStream::Init( NumIdenticalFiles = 0; } + HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp) { m_RealOutStream.Release(); @@ -608,6 +610,7 @@ HRESULT CFolderOutStream::CloseFileWithResOp(Int32 resOp) return m_ExtractCallback->SetOperationResult(resOp); } + HRESULT CFolderOutStream::CloseFile() { return CloseFileWithResOp(m_IsOk ? @@ -615,6 +618,7 @@ HRESULT CFolderOutStream::CloseFile() NExtract::NOperationResult::kDataError); } + HRESULT CFolderOutStream::OpenFile() { if (NumIdenticalFiles == 0) @@ -680,6 +684,7 @@ HRESULT CFolderOutStream::OpenFile() return m_ExtractCallback->PrepareOperation(askMode); } + HRESULT CFolderOutStream::WriteEmptyFiles() { if (m_FileIsOpen) @@ -699,13 +704,15 @@ HRESULT CFolderOutStream::WriteEmptyFiles() return S_OK; } -// This is Write function + HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) { COM_TRY_BEGIN + UInt32 realProcessed = 0; if (processedSize) *processedSize = 0; + while (size != 0) { if (m_FileIsOpen) @@ -732,8 +739,10 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe size -= numBytesToWrite; m_RemainFileSize -= numBytesToWrite; m_PosInFolder += numBytesToWrite; + if (res != S_OK) return res; + if (m_RemainFileSize == 0) { RINOK(CloseFile()); @@ -754,17 +763,27 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe { RINOK(CloseFile()); } + RINOK(result); } + TempBufMode = false; } + if (realProcessed > 0) break; // with this break this function works as Write-Part } else { if (m_CurrentIndex >= m_ExtractStatuses->Size()) - return E_FAIL; + { + // we ignore extra data; + realProcessed += size; + if (processedSize) + *processedSize = realProcessed; + return S_OK; + // return E_FAIL; + } const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; @@ -772,8 +791,10 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe m_RemainFileSize = item.Size; UInt32 fileOffset = item.Offset; + if (fileOffset < m_PosInFolder) return E_FAIL; + if (fileOffset > m_PosInFolder) { UInt32 numBytesToWrite = MyMin(fileOffset - (UInt32)m_PosInFolder, size); @@ -784,6 +805,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe size -= numBytesToWrite; m_PosInFolder += numBytesToWrite; } + if (fileOffset == m_PosInFolder) { RINOK(OpenFile()); @@ -793,21 +815,39 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe } } } + return WriteEmptyFiles(); + COM_TRY_END } + STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { return Write2(data, size, processedSize, true); } -HRESULT CFolderOutStream::FlushCorrupted() + +HRESULT CFolderOutStream::FlushCorrupted(unsigned folderIndex) { + UInt64 remain = GetRemain(); + + if (remain == 0) + { + CMyComPtr<IArchiveExtractCallbackMessage> callbackMessage; + m_ExtractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage); + if (callbackMessage) + { + RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, NExtract::NOperationResult::kDataError)); + } + return S_OK; + } + const unsigned kBufSize = (1 << 10); Byte buf[kBufSize]; for (unsigned i = 0; i < kBufSize; i++) buf[i] = 0; + for (;;) { UInt64 remain = GetRemain(); @@ -819,6 +859,7 @@ HRESULT CFolderOutStream::FlushCorrupted() } } + HRESULT CFolderOutStream::Unsupported() { while (m_CurrentIndex < m_ExtractStatuses->Size()) @@ -838,6 +879,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = m_Database.Items.Size(); @@ -883,10 +925,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CMyComPtr<ICompressCoder> deflateDecoder; NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL; - CMyComPtr<ICompressCoder> lzxDecoder; + CMyComPtr<IUnknown> lzxDecoder; NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL; - CMyComPtr<ICompressCoder> quantumDecoder; + CMyComPtr<IUnknown> quantumDecoder; CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream(); CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec; @@ -968,7 +1010,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, CFolderOutStream *cabFolderOutStream = new CFolderOutStream; CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream); - const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())]; + unsigned folderIndex2 = item.GetFolderIndex(db.Folders.Size()); + const CFolder &folder = db.Folders[folderIndex2]; cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, curUnpack, extractCallback, testMode); @@ -980,6 +1023,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, { case NHeader::NMethod::kNone: break; + case NHeader::NMethod::kMSZip: if (!deflateDecoder) { @@ -988,14 +1032,16 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } cabBlockInStreamSpec->MsZip = true; break; + case NHeader::NMethod::kLZX: if (!lzxDecoder) { lzxDecoderSpec = new NCompress::NLzx::CDecoder; lzxDecoder = lzxDecoderSpec; } - res = lzxDecoderSpec->SetParams(folder.MethodMinor); + res = lzxDecoderSpec->SetParams_and_Alloc(folder.MethodMinor); break; + case NHeader::NMethod::kQuantum: if (!quantumDecoder) { @@ -1004,6 +1050,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } res = quantumDecoderSpec->SetParams(folder.MethodMinor); break; + default: res = E_INVALIDARG; break; @@ -1022,6 +1069,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); bool keepHistory = false; bool keepInputBuffer = false; + bool thereWasNotAlignedChunk = false; for (UInt32 bl = 0; cabFolderOutStream->GetRemain() != 0;) { @@ -1058,6 +1106,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, continue; } } + bl++; if (!keepInputBuffer) @@ -1079,19 +1128,39 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, lps->InSize = totalPacked; RINOK(lps->SetCur()); - UInt64 unpackRemain = cabFolderOutStream->GetRemain(); - const UInt32 kBlockSizeMax = (1 << 15); - if (unpackRemain > kBlockSizeMax) - unpackRemain = kBlockSizeMax; - if (unpackRemain > unpackSize) - unpackRemain = unpackSize; + + /* We don't try to reduce last block. + Note that LZX converts data with x86 filter. + and filter needs larger input data than reduced size. + It's simpler to decompress full chunk here. + also we need full block for quantum for more integrity checks */ + + if (unpackSize > kBlockSizeMax) + { + res = S_FALSE; + break; + } + + if (unpackSize != kBlockSizeMax) + { + if (thereWasNotAlignedChunk) + { + res = S_FALSE; + break; + } + thereWasNotAlignedChunk = true; + } + + UInt64 unpackSize64 = unpackSize; + UInt32 packSizeChunk = cabBlockInStreamSpec->GetPackSizeAvail(); switch (folder.GetMethod()) { case NHeader::NMethod::kNone: - res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL); break; + case NHeader::NMethod::kMSZip: deflateDecoderSpec->Set_KeepHistory(keepHistory); /* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block. @@ -1100,7 +1169,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Maybe we also should ignore that error? Or we should extract full file and show the warning? */ deflateDecoderSpec->Set_NeedFinishInput(true); - res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL); if (res == S_OK) { if (!deflateDecoderSpec->IsFinished()) @@ -1108,16 +1177,24 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (!deflateDecoderSpec->IsFinalBlock()) res = S_FALSE; } - break; + case NHeader::NMethod::kLZX: lzxDecoderSpec->SetKeepHistory(keepHistory); - res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + lzxDecoderSpec->KeepHistoryForNext = true; + + res = lzxDecoderSpec->Code(cabBlockInStreamSpec->GetData(), packSizeChunk, unpackSize); + + if (res == S_OK) + res = WriteStream(outStream, + lzxDecoderSpec->GetUnpackData(), + lzxDecoderSpec->GetUnpackSize()); break; + case NHeader::NMethod::kQuantum: - quantumDecoderSpec->SetKeepHistory(keepHistory); - res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); - break; + res = quantumDecoderSpec->Code(cabBlockInStreamSpec->GetData(), + packSizeChunk, outStream, unpackSize, keepHistory); + break; } if (res != S_OK) @@ -1135,17 +1212,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, RINOK(cabFolderOutStream->WriteEmptyFiles()); } } + if (res != S_OK || cabFolderOutStream->GetRemain() != 0) { - RINOK(cabFolderOutStream->FlushCorrupted()); + RINOK(cabFolderOutStream->FlushCorrupted(folderIndex2)); } + totalUnPacked += curUnpack; } return S_OK; + COM_TRY_END } + STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { *numItems = m_Database.Items.Size(); |