diff options
Diffstat (limited to '7zip/Archive/Cab/CabHandler.cpp')
-rwxr-xr-x | 7zip/Archive/Cab/CabHandler.cpp | 794 |
1 files changed, 485 insertions, 309 deletions
diff --git a/7zip/Archive/Cab/CabHandler.cpp b/7zip/Archive/Cab/CabHandler.cpp index 669de218..c3dd061f 100755 --- a/7zip/Archive/Cab/CabHandler.cpp +++ b/7zip/Archive/Cab/CabHandler.cpp @@ -1,9 +1,10 @@ -// Cab/Handler.cpp +// CabHandler.cpp #include "StdAfx.h" #include "Common/StringConvert.h" #include "Common/Defs.h" +#include "Common/Alloc.h" #include "Common/UTFConvert.h" #include "Common/ComTry.h" #include "Common/IntToString.h" @@ -11,32 +12,45 @@ #include "Windows/PropVariant.h" #include "Windows/Time.h" -#include "CabCopyDecoder.h" -#include "LZXDecoder.h" -#include "MSZipDecoder.h" - #include "CabHandler.h" +#include "CabBlockInStream.h" -#include "../../Common/ProgressUtils.h" +#include "../../Compress/Copy/CopyCoder.h" +#include "../../Compress/Deflate/DeflateDecoder.h" +#include "../../Compress/Lzx/LzxDecoder.h" +#include "../../Compress/Quantum/QuantumDecoder.h" using namespace NWindows; -using namespace NTime; namespace NArchive { namespace NCab { +// #define _CAB_DETAILS + +#ifdef _CAB_DETAILS +enum +{ + kpidBlockReal = kpidUserDefined, + kpidOffset, + kpidVolume, +}; +#endif + STATPROPSTG kProperties[] = { { NULL, kpidPath, VT_BSTR}, - { NULL, kpidIsFolder, VT_BOOL}, + // { NULL, kpidIsFolder, VT_BOOL}, { NULL, kpidSize, VT_UI8}, { NULL, kpidLastWriteTime, VT_FILETIME}, { NULL, kpidAttributes, VT_UI4}, - { NULL, kpidMethod, VT_BSTR}, - // { NULL, kpidDictionarySize, VT_UI4}, - - { NULL, kpidBlock, VT_UI4} + { NULL, kpidBlock, VT_I4} + #ifdef _CAB_DETAILS + , + { L"BlockReal", kpidBlockReal, VT_UI4}, + { L"Offset", kpidOffset, VT_UI4}, + { L"Volume", kpidVolume, VT_UI4} + #endif }; static const int kNumProperties = sizeof(kProperties) / sizeof(kProperties[0]); @@ -72,7 +86,10 @@ STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, const STATPROPSTG &srcItem = kProperties[index]; *propID = srcItem.propid; *varType = srcItem.vt; - *name = 0; + if (srcItem.lpwstrName == 0) + *name = 0; + else + *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } @@ -92,31 +109,35 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va { COM_TRY_BEGIN NWindows::NCOM::CPropVariant propVariant; - const CItem &fileInfo = m_Files[index]; + + const CMvItem &mvItem = m_Database.Items[index]; + const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; + int itemIndex = mvItem.ItemIndex; + const CItem &item = db.Items[itemIndex]; switch(propID) { case kpidPath: - if (fileInfo.IsNameUTF()) + if (item.IsNameUTF()) { UString unicodeName; - if (!ConvertUTF8ToUnicode(fileInfo.Name, unicodeName)) + if (!ConvertUTF8ToUnicode(item.Name, unicodeName)) propVariant = L""; else propVariant = unicodeName; } else - propVariant = MultiByteToUnicodeString(fileInfo.Name, CP_ACP); + propVariant = MultiByteToUnicodeString(item.Name, CP_ACP); break; case kpidIsFolder: - propVariant = fileInfo.IsDirectory(); + propVariant = item.IsDirectory(); break; case kpidSize: - propVariant = fileInfo.UnPackSize; + propVariant = item.Size; break; case kpidLastWriteTime: { FILETIME localFileTime, utcFileTime; - if (DosTimeToFileTime(fileInfo.Time, localFileTime)) + if (NTime::DosTimeToFileTime(item.Time, localFileTime)) { if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; @@ -127,21 +148,17 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va break; } case kpidAttributes: - propVariant = fileInfo.GetWinAttributes(); + propVariant = item.GetWinAttributes(); break; case kpidMethod: { - UInt16 realFolderIndex = NHeader::NFolderIndex::GetRealFolderIndex( - m_Folders.Size(), fileInfo.FolderIndex); - const NHeader::CFolder &folder = m_Folders[realFolderIndex]; - UString method; + UInt16 realFolderIndex = item.GetFolderIndex(db.Folders.Size()); + const CFolder &folder = db.Folders[realFolderIndex]; int methodIndex = folder.GetCompressionMethod(); - if (methodIndex < kNumMethods) - method = kMethods[methodIndex]; - else - method = kUnknownMethod; - if (methodIndex == NHeader::NCompressionMethodMajor::kLZX) + UString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod; + if (methodIndex == NHeader::NCompressionMethodMajor::kLZX || + methodIndex == NHeader::NCompressionMethodMajor::kQuantum) { method += L":"; wchar_t temp[32]; @@ -152,14 +169,29 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va break; } case kpidBlock: - propVariant = UInt32(fileInfo.FolderIndex); + propVariant = (Int32)m_Database.GetFolderIndex(&mvItem); break; + + #ifdef _CAB_DETAILS + + case kpidBlockReal: + propVariant = UInt32(item.FolderIndex); + break; + case kpidOffset: + propVariant = (UInt32)item.Offset; + break; + case kpidVolume: + propVariant = (UInt32)mvItem.VolumeIndex; + break; + + #endif } propVariant.Detach(value); return S_OK; COM_TRY_END } +/* class CPropgressImp: public CProgressVirt { CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback; @@ -183,36 +215,113 @@ STDMETHODIMP CPropgressImp::SetCompleted(const UInt64 *numFiles) return m_OpenArchiveCallback->SetCompleted(numFiles, NULL); return S_OK; } +*/ STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openArchiveCallback) { COM_TRY_BEGIN - m_Stream.Release(); - // try + Close(); + HRESULT res; + CInArchive archive; + CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; { - CInArchive archive; - m_Files.Clear(); - CPropgressImp progressImp; - progressImp.Init(openArchiveCallback); - RINOK(archive.Open(inStream, maxCheckStartPosition, - m_ArchiveInfo, m_Folders, m_Files, &progressImp)); - m_Stream = inStream; + CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback; + openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback); + } + + CMyComPtr<IInStream> nextStream = inStream; + bool prevChecked = false; + UInt64 numItems = 0; + try + { + while(nextStream != 0) + { + CDatabaseEx db; + db.Stream = nextStream; + res = archive.Open(maxCheckStartPosition, db); + if (res == S_OK) + { + if (!m_Database.Volumes.IsEmpty()) + { + const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0]; + if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID || + dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) != + db.ArchiveInfo.CabinetNumber) + res = S_FALSE; + } + } + if (res == S_OK) + m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db); + else if (res != S_FALSE) + return res; + else + { + if (m_Database.Volumes.IsEmpty()) + return S_FALSE; + if (prevChecked) + break; + prevChecked = true; + } + + numItems += db.Items.Size(); + RINOK(openArchiveCallback->SetCompleted(&numItems, NULL)); + + nextStream = 0; + while(true) + { + const COtherArchive *otherArchive = 0; + if (!prevChecked) + { + const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo; + if (ai.IsTherePrev()) + otherArchive = &ai.PreviousArchive; + else + prevChecked = true; + } + if (otherArchive == 0) + { + const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo; + if (ai.IsThereNext()) + otherArchive = &ai.NextArchive; + } + if (!otherArchive) + break; + const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP); + HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); + if (result == S_OK) + break; + if (result != S_FALSE) + return result; + if (prevChecked) + break; + prevChecked = true; + } + } + if (res == S_OK) + { + m_Database.FillSortAndShrink(); + if (!m_Database.Check()) + res = S_FALSE; + } } - /* catch(...) { - return S_FALSE; + res = S_FALSE; + } + if (res != S_OK) + { + Close(); + return res; } - */ COM_TRY_END return S_OK; } STDMETHODIMP CHandler::Close() { - m_Stream.Release(); + m_Database.Clear(); return S_OK; } @@ -224,405 +333,472 @@ public: MY_UNKNOWN_IMP STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); - STDMETHOD(WritePart)(const void *data, UInt32 size, UInt32 *processedSize); private: - const CObjectVector<NHeader::CFolder> *m_Folders; - const CObjectVector<CItem> *m_Files; - const CRecordVector<int> *m_FileIndexes; + const CMvDatabaseEx *m_Database; const CRecordVector<bool> *m_ExtractStatuses; int m_StartIndex; int m_CurrentIndex; - int m_NumFiles; - UInt64 m_CurrentDataPos; CMyComPtr<IArchiveExtractCallback> m_ExtractCallback; bool m_TestMode; + CMyComPtr<ISequentialOutStream> m_RealOutStream; + + bool m_IsOk; bool m_FileIsOpen; - CMyComPtr<ISequentialOutStream> realOutStream; - UInt64 m_FilePos; + UInt64 m_RemainFileSize; + UInt64 m_FolderSize; + UInt64 m_PosInFolder; - HRESULT OpenFile(int indexIndex, ISequentialOutStream **realOutStream); - HRESULT WriteEmptyFiles(); - UInt64 m_StartImportantTotalUnPacked; + HRESULT OpenFile(); + HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK); public: + HRESULT WriteEmptyFiles(); + void Init( - const CObjectVector<NHeader::CFolder> *folders, - const CObjectVector<CItem> *files, - const CRecordVector<int> *fileIndices, + const CMvDatabaseEx *database, const CRecordVector<bool> *extractStatuses, int startIndex, - int numFiles, + UInt64 folderSize, IArchiveExtractCallback *extractCallback, - UInt64 startImportantTotalUnPacked, bool testMode); HRESULT FlushCorrupted(); HRESULT Unsupported(); + + UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; } + UInt64 GetPosInFolder() const { return m_PosInFolder; } }; void CCabFolderOutStream::Init( - const CObjectVector<NHeader::CFolder> *folders, - const CObjectVector<CItem> *files, - const CRecordVector<int> *fileIndices, + const CMvDatabaseEx *database, const CRecordVector<bool> *extractStatuses, int startIndex, - int numFiles, + UInt64 folderSize, IArchiveExtractCallback *extractCallback, - UInt64 startImportantTotalUnPacked, bool testMode) { - m_Folders = folders; - m_Files = files; - m_FileIndexes = fileIndices; + m_Database = database; m_ExtractStatuses = extractStatuses; m_StartIndex = startIndex; - m_NumFiles = numFiles; + m_FolderSize = folderSize; + m_ExtractCallback = extractCallback; - m_StartImportantTotalUnPacked = startImportantTotalUnPacked; m_TestMode = testMode; m_CurrentIndex = 0; + m_PosInFolder = 0; m_FileIsOpen = false; + m_IsOk = true; } -HRESULT CCabFolderOutStream::OpenFile(int indexIndex, ISequentialOutStream **realOutStream) +HRESULT CCabFolderOutStream::OpenFile() { - // RINOK(m_ExtractCallback->SetCompleted(&m_StartImportantTotalUnPacked)); - - int fullIndex = m_StartIndex + indexIndex; - - Int32 askMode; - if((*m_ExtractStatuses)[fullIndex]) - askMode = m_TestMode ? - NArchive::NExtract::NAskMode::kTest : - NArchive::NExtract::NAskMode::kExtract; - else + Int32 askMode = (*m_ExtractStatuses)[m_CurrentIndex] ? (m_TestMode ? + NExtract::NAskMode::kTest : + NExtract::NAskMode::kExtract) : + NExtract::NAskMode::kSkip; + RINOK(m_ExtractCallback->GetStream(m_StartIndex + m_CurrentIndex, &m_RealOutStream, askMode)); + if (!m_RealOutStream && !m_TestMode) askMode = NArchive::NExtract::NAskMode::kSkip; - - int index = (*m_FileIndexes)[fullIndex]; - const CItem &fileInfo = (*m_Files)[index]; - UInt16 realFolderIndex = NHeader::NFolderIndex::GetRealFolderIndex( - m_Folders->Size(), fileInfo.FolderIndex); - - RINOK(m_ExtractCallback->GetStream(index, realOutStream, askMode)); - - UInt64 currentUnPackSize = fileInfo.UnPackSize; - - bool mustBeProcessedAnywhere = (indexIndex < m_NumFiles - 1); - - if (realOutStream || mustBeProcessedAnywhere) - { - if (!realOutStream && !m_TestMode) - askMode = NArchive::NExtract::NAskMode::kSkip; - RINOK(m_ExtractCallback->PrepareOperation(askMode)); - return S_OK; - } - else - return S_FALSE; + return m_ExtractCallback->PrepareOperation(askMode); } - HRESULT CCabFolderOutStream::WriteEmptyFiles() { - for(;m_CurrentIndex < m_NumFiles; m_CurrentIndex++) + if (m_FileIsOpen) + return S_OK; + for(;m_CurrentIndex < m_ExtractStatuses->Size(); m_CurrentIndex++) { - int index = (*m_FileIndexes)[m_StartIndex + m_CurrentIndex]; - const CItem &fileInfo = (*m_Files)[index]; - if (fileInfo.UnPackSize != 0) + const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; + const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + UInt64 fileSize = item.Size; + if (fileSize != 0) return S_OK; - realOutStream.Release(); - HRESULT result = OpenFile(m_CurrentIndex, &realOutStream); - realOutStream.Release(); - if (result == S_FALSE) - { - } - else if (result == S_OK) - { - RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); - } - else - return result; + HRESULT result = OpenFile(); + m_RealOutStream.Release(); + RINOK(result); + RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); } return S_OK; } -STDMETHODIMP CCabFolderOutStream::Write(const void *data, - UInt32 size, UInt32 *processedSize) +// This is Write function +HRESULT CCabFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK) { - UInt32 processedSizeReal = 0; - while(m_CurrentIndex < m_NumFiles) + UInt32 realProcessed = 0; + if (processedSize != NULL) + *processedSize = 0; + while(size != 0) { if (m_FileIsOpen) { - int index = (*m_FileIndexes)[m_StartIndex + m_CurrentIndex]; - const CItem &fileInfo = (*m_Files)[index]; - UInt64 fileSize = fileInfo.UnPackSize; - - UInt32 numBytesToWrite = (UInt32)MyMin(fileSize - m_FilePos, - UInt64(size - processedSizeReal)); - - UInt32 processedSizeLocal; - if (!realOutStream) - { - processedSizeLocal = numBytesToWrite; - } - else + UInt32 numBytesToWrite = (UInt32)MyMin(m_RemainFileSize, (UInt64)(size)); + HRESULT res = S_OK; + if (numBytesToWrite > 0) { - RINOK(realOutStream->Write((const Byte *)data + processedSizeReal, numBytesToWrite, &processedSizeLocal)); + if (!isOK) + m_IsOk = false; + if (m_RealOutStream) + { + UInt32 processedSizeLocal = 0; + res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal); + numBytesToWrite = processedSizeLocal; + } } - m_FilePos += processedSizeLocal; - processedSizeReal += processedSizeLocal; - if (m_FilePos == fileInfo.UnPackSize) + realProcessed += numBytesToWrite; + if (processedSize != NULL) + *processedSize = realProcessed; + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_RemainFileSize -= numBytesToWrite; + m_PosInFolder += numBytesToWrite; + if (res != S_OK) + return res; + if (m_RemainFileSize == 0) { - realOutStream.Release(); - RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); + m_RealOutStream.Release(); + RINOK(m_ExtractCallback->SetOperationResult( + m_IsOk ? + NArchive::NExtract::NOperationResult::kOK: + NArchive::NExtract::NOperationResult::kDataError)); m_FileIsOpen = false; - m_CurrentIndex++; - } - if (processedSizeReal == size) - { - RINOK(WriteEmptyFiles()); - if (processedSize != NULL) - *processedSize = processedSizeReal; - return S_OK; } + if (realProcessed > 0) + break; // with this break this function works as Write-Part } else { - HRESULT result = OpenFile(m_CurrentIndex, &realOutStream); - if (result != S_FALSE && result != S_OK) - return result; - m_FileIsOpen = true; - m_FilePos = 0; + if (m_CurrentIndex >= m_ExtractStatuses->Size()) + return E_FAIL; + + const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; + const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + + m_RemainFileSize = item.Size; + + UInt32 fileOffset = item.Offset; + if (fileOffset < m_PosInFolder) + return E_FAIL; + if (fileOffset > m_PosInFolder) + { + UInt32 numBytesToWrite = (UInt32)MyMin((UInt64)fileOffset - m_PosInFolder, UInt64(size)); + realProcessed += numBytesToWrite; + if (processedSize != NULL) + *processedSize = realProcessed; + data = (const void *)((const Byte *)data + numBytesToWrite); + size -= numBytesToWrite; + m_PosInFolder += numBytesToWrite; + } + if (fileOffset == m_PosInFolder) + { + RINOK(OpenFile()); + m_FileIsOpen = true; + m_CurrentIndex++; + m_IsOk = true; + } } } - if (processedSize != NULL) - *processedSize = size; - return S_OK; + return WriteEmptyFiles(); +} + +STDMETHODIMP CCabFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + return Write2(data, size, processedSize, true); } HRESULT CCabFolderOutStream::FlushCorrupted() { - // UInt32 processedSizeReal = 0; - while(m_CurrentIndex < m_NumFiles) + const UInt32 kBufferSize = (1 << 10); + Byte buffer[kBufferSize]; + for (int i = 0; i < kBufferSize; i++) + buffer[i] = 0; + while(true) { - if (m_FileIsOpen) - { - int index = (*m_FileIndexes)[m_StartIndex + m_CurrentIndex]; - const CItem &fileInfo = (*m_Files)[index]; - UInt64 fileSize = fileInfo.UnPackSize; - - realOutStream.Release(); - RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kCRCError)); - m_FileIsOpen = false; - m_CurrentIndex++; - } - else - { - HRESULT result = OpenFile(m_CurrentIndex, &realOutStream); - if (result != S_FALSE && result != S_OK) - return result; - m_FileIsOpen = true; - } + UInt64 remain = GetRemain(); + if (remain == 0) + return S_OK; + UInt32 size = (UInt32)MyMin(remain, (UInt64)kBufferSize); + UInt32 processedSizeLocal = 0; + RINOK(Write2(buffer, size, &processedSizeLocal, false)); } - return S_OK; } HRESULT CCabFolderOutStream::Unsupported() { - while(m_CurrentIndex < m_NumFiles) + while(m_CurrentIndex < m_ExtractStatuses->Size()) { - HRESULT result = OpenFile(m_CurrentIndex, &realOutStream); + HRESULT result = OpenFile(); if (result != S_FALSE && result != S_OK) return result; - realOutStream.Release(); + m_RealOutStream.Release(); RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod)); m_CurrentIndex++; } return S_OK; } -STDMETHODIMP CCabFolderOutStream::WritePart(const void *data, - UInt32 size, UInt32 *processedSize) -{ - return Write(data, size, processedSize); -} - STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, Int32 _aTestMode, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == UInt32(-1)); + bool allFilesMode = (numItems == (UInt32)(-1)); if (allFilesMode) - numItems = m_Files.Size(); + numItems = m_Database.Items.Size(); if(numItems == 0) return S_OK; bool testMode = (_aTestMode != 0); - UInt64 censoredTotalUnPacked = 0, importantTotalUnPacked = 0; + UInt64 totalUnPacked = 0; int lastIndex = 0; - CRecordVector<int> folderIndexes; - CRecordVector<int> importantIndices; - CRecordVector<bool> extractStatuses; UInt32 i; + int lastFolder = -2; + UInt64 lastFolderSize = 0; for(i = 0; i < numItems; i++) { int index = allFilesMode ? i : indices[i]; - const CItem &fileInfo = m_Files[index]; - censoredTotalUnPacked += fileInfo.UnPackSize; - - int folderIndex = fileInfo.FolderIndex; - if (folderIndexes.IsEmpty()) - folderIndexes.Add(folderIndex); - else - { - if (folderIndex != folderIndexes.Back()) - folderIndexes.Add(folderIndex); - } - - int j; - for(j = index - 1; j >= lastIndex; j--) - if(m_Files[j].FolderIndex != folderIndex) - break; - for(j++; j <= index; j++) - { - const CItem &fileInfo = m_Files[j]; - importantTotalUnPacked += fileInfo.UnPackSize; - importantIndices.Add(j); - extractStatuses.Add(j == index); - } - lastIndex = index + 1; + const CMvItem &mvItem = m_Database.Items[index]; + const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + if (item.IsDirectory()) + continue; + int folderIndex = m_Database.GetFolderIndex(&mvItem); + if (folderIndex != lastFolder) + totalUnPacked += lastFolderSize; + lastFolder = folderIndex; + lastFolderSize = item.GetEndOffset(); } + totalUnPacked += lastFolderSize; + + extractCallback->SetTotal(totalUnPacked); - extractCallback->SetTotal(importantTotalUnPacked); - UInt64 currentImportantTotalUnPacked = 0; - UInt64 currentImportantTotalPacked = 0; + totalUnPacked = 0; - CCopyDecoder *storeDecoderSpec = NULL; - CMyComPtr<ICompressCoder> storeDecoder; + NCompress::CCopyCoder *copyCoderSpec = NULL; + CMyComPtr<ICompressCoder> copyCoder; - NMSZip::CDecoder *msZipDecoderSpec = NULL; - CMyComPtr<ICompressCoder> msZipDecoder; + NCompress::NDeflate::NDecoder::CCOMCoder *deflateDecoderSpec = NULL; + CMyComPtr<ICompressCoder> deflateDecoder; - NLZX::CDecoder *lzxDecoderSpec = NULL; + NCompress::NLzx::CDecoder *lzxDecoderSpec = NULL; CMyComPtr<ICompressCoder> lzxDecoder; + NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL; + CMyComPtr<ICompressCoder> quantumDecoder; - int curImportantIndexIndex = 0; - UInt64 totalFolderUnPacked; - for(i = 0; i < (UInt32)folderIndexes.Size(); i++, currentImportantTotalUnPacked += totalFolderUnPacked) + CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream(); + CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec; + if (!cabBlockInStreamSpec->Create()) + return E_OUTOFMEMORY; + + CRecordVector<bool> extractStatuses; + for(i = 0; i < numItems;) { - int folderIndex = folderIndexes[i]; - UInt16 realFolderIndex = NHeader::NFolderIndex::GetRealFolderIndex( - m_Folders.Size(), folderIndex); - - RINOK(extractCallback->SetCompleted(¤tImportantTotalUnPacked)); - totalFolderUnPacked = 0; - int j; - for (j = curImportantIndexIndex; j < importantIndices.Size(); j++) + int index = allFilesMode ? i : indices[i]; + + const CMvItem &mvItem = m_Database.Items[index]; + const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; + int itemIndex = mvItem.ItemIndex; + const CItem &item = db.Items[itemIndex]; + + i++; + if (item.IsDirectory()) { - const CItem &fileInfo = m_Files[importantIndices[j]]; - if (fileInfo.FolderIndex != folderIndex) + Int32 askMode= testMode ? + NArchive::NExtract::NAskMode::kTest : + NArchive::NExtract::NAskMode::kExtract; + CMyComPtr<ISequentialOutStream> realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + RINOK(extractCallback->PrepareOperation(askMode)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); + continue; + } + int folderIndex = m_Database.GetFolderIndex(&mvItem); + if (folderIndex < 0) + { + // If we need previous archive + Int32 askMode= testMode ? + NArchive::NExtract::NAskMode::kTest : + NArchive::NExtract::NAskMode::kExtract; + CMyComPtr<ISequentialOutStream> realOutStream; + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); + RINOK(extractCallback->PrepareOperation(askMode)); + realOutStream.Release(); + RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kDataError)); + continue; + } + int startIndex2 = m_Database.FolderStartFileIndex[folderIndex]; + int startIndex = startIndex2; + extractStatuses.Clear(); + for (; startIndex < index; startIndex++) + extractStatuses.Add(false); + extractStatuses.Add(true); + startIndex++; + UInt64 curUnpack = item.GetEndOffset(); + for(;i < numItems; i++) + { + int indexNext = allFilesMode ? i : indices[i]; + const CMvItem &mvItem = m_Database.Items[indexNext]; + const CItem &item = m_Database.Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + if (item.IsDirectory()) + continue; + int newFolderIndex = m_Database.GetFolderIndex(&mvItem); + + if (newFolderIndex != folderIndex) break; - totalFolderUnPacked += fileInfo.UnPackSize; + for (; startIndex < indexNext; startIndex++) + extractStatuses.Add(false); + extractStatuses.Add(true); + startIndex++; + curUnpack = item.GetEndOffset(); } + + RINOK(extractCallback->SetCompleted(&totalUnPacked)); - CCabFolderOutStream *cabFolderOutStream = new CCabFolderOutStream; + CCabFolderOutStream *cabFolderOutStream = new CCabFolderOutStream; CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream); - const NHeader::CFolder &folder = m_Folders[realFolderIndex]; + const CFolder &folder = db.Folders[item.GetFolderIndex(db.Folders.Size())]; - cabFolderOutStream->Init(&m_Folders, &m_Files, &importantIndices, - &extractStatuses, curImportantIndexIndex, j - curImportantIndexIndex, - extractCallback, currentImportantTotalUnPacked, - folder.GetCompressionMethod() == NHeader::NCompressionMethodMajor::kQuantum? - true: testMode); - - curImportantIndexIndex = j; - - UInt64 pos = folder.DataStart; // test it (+ archiveStart) - RINOK(m_Stream->Seek(pos, STREAM_SEEK_SET, NULL)); - - CLocalProgress *localProgressSpec = new CLocalProgress; - CMyComPtr<ICompressProgressInfo> progress = localProgressSpec; - localProgressSpec->Init(extractCallback, false); - - CLocalCompressProgressInfo *localCompressProgressSpec = - new CLocalCompressProgressInfo; - CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec; - localCompressProgressSpec->Init(progress, - NULL, ¤tImportantTotalUnPacked); - - Byte reservedSize = m_ArchiveInfo.ReserveBlockPresent() ? - m_ArchiveInfo.PerDataSizes.PerDatablockAreaSize : 0; + cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2, + curUnpack, extractCallback, testMode); + cabBlockInStreamSpec->MsZip = false; switch(folder.GetCompressionMethod()) { case NHeader::NCompressionMethodMajor::kNone: - { - if(storeDecoderSpec == NULL) + if(copyCoderSpec == NULL) { - storeDecoderSpec = new CCopyDecoder; - storeDecoder = storeDecoderSpec; - } - try - { - storeDecoderSpec->SetParams(reservedSize, folder.NumDataBlocks); - RINOK(storeDecoder->Code(m_Stream, outStream, - NULL, &totalFolderUnPacked, compressProgress)); - } - catch(...) - { - RINOK(cabFolderOutStream->FlushCorrupted()); - continue; + copyCoderSpec = new NCompress::CCopyCoder; + copyCoder = copyCoderSpec; } break; - } case NHeader::NCompressionMethodMajor::kMSZip: - { - if(lzxDecoderSpec == NULL) + if(deflateDecoderSpec == NULL) { - msZipDecoderSpec = new NMSZip::CDecoder; - msZipDecoder = msZipDecoderSpec; + deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder; + deflateDecoder = deflateDecoderSpec; } - try + cabBlockInStreamSpec->MsZip = true; + break; + case NHeader::NCompressionMethodMajor::kLZX: + if(lzxDecoderSpec == NULL) { - msZipDecoderSpec->SetParams(reservedSize, folder.NumDataBlocks); - RINOK(msZipDecoder->Code(m_Stream, outStream, - NULL, &totalFolderUnPacked, compressProgress)); + lzxDecoderSpec = new NCompress::NLzx::CDecoder; + lzxDecoder = lzxDecoderSpec; } - catch(...) + RINOK(lzxDecoderSpec->SetParams(folder.CompressionTypeMinor)); + break; + case NHeader::NCompressionMethodMajor::kQuantum: + if(quantumDecoderSpec == NULL) { - RINOK(cabFolderOutStream->FlushCorrupted()); - continue; + quantumDecoderSpec = new NCompress::NQuantum::CDecoder; + quantumDecoder = quantumDecoderSpec; } + quantumDecoderSpec->SetParams(folder.CompressionTypeMinor); break; + default: + { + RINOK(cabFolderOutStream->Unsupported()); + totalUnPacked += curUnpack; + continue; } - case NHeader::NCompressionMethodMajor::kLZX: + } + + cabBlockInStreamSpec->InitForNewFolder(); + + HRESULT res = S_OK; + + { + int volIndex = mvItem.VolumeIndex; + int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); + bool keepHistory = false; + bool keepInputBuffer = false; + for (UInt32 f = 0; cabFolderOutStream->GetRemain() != 0;) { - if(lzxDecoderSpec == NULL) + if (volIndex >= m_Database.Volumes.Size()) { - lzxDecoderSpec = new NLZX::CDecoder; - lzxDecoder = lzxDecoderSpec; + res = S_FALSE; + break; } - try + + const CDatabaseEx &db = m_Database.Volumes[volIndex]; + const CFolder &folder = db.Folders[locFolderIndex]; + if (f == 0) { - lzxDecoderSpec->SetParams(reservedSize, folder.NumDataBlocks, - folder.CompressionTypeMinor); - RINOK(lzxDecoder->Code(m_Stream, outStream, - NULL, &totalFolderUnPacked, compressProgress)); + cabBlockInStreamSpec->SetStream(db.Stream); + cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize(); + RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL)); } - catch(...) + if (f == folder.NumDataBlocks) { - RINOK(cabFolderOutStream->FlushCorrupted()); + volIndex++; + locFolderIndex = 0; + f = 0; continue; } - break; + f++; + + cabBlockInStreamSpec->DataError = false; + + if (!keepInputBuffer) + cabBlockInStreamSpec->InitForNewBlock(); + + UInt32 packSize, unpackSize; + res = cabBlockInStreamSpec->PreRead(packSize, unpackSize); + if (res == S_FALSE) + break; + RINOK(res); + keepInputBuffer = (unpackSize == 0); + if (keepInputBuffer) + continue; + + + UInt64 totalUnPacked2 = totalUnPacked + cabFolderOutStream->GetPosInFolder(); + RINOK(extractCallback->SetCompleted(&totalUnPacked2)); + UInt64 unpackRemain = cabFolderOutStream->GetRemain(); + + const UInt32 kBlockSizeMax = (1 << 15); + if (unpackRemain > kBlockSizeMax) + unpackRemain = kBlockSizeMax; + if (unpackRemain > unpackSize) + unpackRemain = unpackSize; + + switch(folder.GetCompressionMethod()) + { + case NHeader::NCompressionMethodMajor::kNone: + res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + break; + case NHeader::NCompressionMethodMajor::kMSZip: + deflateDecoderSpec->SetKeepHistory(keepHistory); + res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + break; + case NHeader::NCompressionMethodMajor::kLZX: + lzxDecoderSpec->SetKeepHistory(keepHistory, cabBlockInStreamSpec->GetAlign()); + res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + break; + case NHeader::NCompressionMethodMajor::kQuantum: + quantumDecoderSpec->SetKeepHistory(keepHistory); + res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + break; + } + if (res != S_OK) + { + if (res != S_FALSE) + RINOK(res); + break; + } + keepHistory = true; + } + if (res == S_OK) + { + RINOK(cabFolderOutStream->WriteEmptyFiles()); } - default: - RINOK(cabFolderOutStream->Unsupported()); - // return E_FAIL; } + if (res != S_OK || cabFolderOutStream->GetRemain() != 0) + { + RINOK(cabFolderOutStream->FlushCorrupted()); + } + totalUnPacked += curUnpack; } return S_OK; COM_TRY_END @@ -631,9 +807,9 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) { COM_TRY_BEGIN - *numItems = m_Files.Size(); + *numItems = m_Database.Items.Size(); return S_OK; COM_TRY_END } -}}
\ No newline at end of file +}} |