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 '7zip/Archive/Cab/CabHandler.cpp')
-rwxr-xr-x7zip/Archive/Cab/CabHandler.cpp794
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(&currentImportantTotalUnPacked));
- 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, &currentImportantTotalUnPacked);
-
- 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
+}}