📄 cabhandler.cpp
字号:
return S_FALSE;
}
HRESULT CCabFolderOutStream::WriteEmptyFiles()
{
for(;m_CurrentIndex < m_NumFiles; m_CurrentIndex++)
{
int index = (*m_FileIndexes)[m_StartIndex + m_CurrentIndex];
const CItem &fileInfo = (*m_Files)[index];
if (fileInfo.UnPackSize != 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;
}
return S_OK;
}
STDMETHODIMP CCabFolderOutStream::Write(const void *data,
UINT32 size, UINT32 *processedSize)
{
UINT32 processedSizeReal = 0;
while(m_CurrentIndex < m_NumFiles)
{
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
{
RINOK(realOutStream->Write((const BYTE *)data + processedSizeReal, numBytesToWrite, &processedSizeLocal));
}
m_FilePos += processedSizeLocal;
processedSizeReal += processedSizeLocal;
if (m_FilePos == fileInfo.UnPackSize)
{
realOutStream.Release();
RINOK(m_ExtractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
m_FileIsOpen = false;
m_CurrentIndex++;
}
if (processedSizeReal == size)
{
RINOK(WriteEmptyFiles());
if (processedSize != NULL)
*processedSize = processedSizeReal;
return S_OK;
}
}
else
{
HRESULT result = OpenFile(m_CurrentIndex, &realOutStream);
if (result != S_FALSE && result != S_OK)
return result;
m_FileIsOpen = true;
m_FilePos = 0;
}
}
if (processedSize != NULL)
*processedSize = size;
return S_OK;
}
HRESULT CCabFolderOutStream::FlushCorrupted()
{
// UINT32 processedSizeReal = 0;
while(m_CurrentIndex < m_NumFiles)
{
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;
}
}
return S_OK;
}
HRESULT CCabFolderOutStream::Unsupported()
{
while(m_CurrentIndex < m_NumFiles)
{
HRESULT result = OpenFile(m_CurrentIndex, &realOutStream);
if (result != S_FALSE && result != S_OK)
return result;
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));
if (allFilesMode)
numItems = m_Files.Size();
if(numItems == 0)
return S_OK;
bool testMode = (_aTestMode != 0);
UINT64 censoredTotalUnPacked = 0, importantTotalUnPacked = 0;
int lastIndex = 0;
CRecordVector<int> folderIndexes;
CRecordVector<int> importantIndices;
CRecordVector<bool> extractStatuses;
UINT32 i;
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);
}
for(int 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;
}
extractCallback->SetTotal(importantTotalUnPacked);
UINT64 currentImportantTotalUnPacked = 0;
UINT64 currentImportantTotalPacked = 0;
CCopyDecoder *storeDecoderSpec = NULL;
CMyComPtr<ICompressCoder> storeDecoder;
NMSZip::CDecoder *msZipDecoderSpec = NULL;
CMyComPtr<ICompressCoder> msZipDecoder;
NLZX::CDecoder *lzxDecoderSpec = NULL;
CMyComPtr<ICompressCoder> lzxDecoder;
int curImportantIndexIndex = 0;
UINT64 totalFolderUnPacked;
for(i = 0; i < (UINT32)folderIndexes.Size(); i++, currentImportantTotalUnPacked += totalFolderUnPacked)
{
int folderIndex = folderIndexes[i];
UINT16 realFolderIndex = NHeader::NFolderIndex::GetRealFolderIndex(
m_Folders.Size(), folderIndex);
RINOK(extractCallback->SetCompleted(¤tImportantTotalUnPacked));
totalFolderUnPacked = 0;
for (int j = curImportantIndexIndex; j < importantIndices.Size(); j++)
{
const CItem &fileInfo = m_Files[importantIndices[j]];
if (fileInfo.FolderIndex != folderIndex)
break;
totalFolderUnPacked += fileInfo.UnPackSize;
}
CCabFolderOutStream *cabFolderOutStream = new CCabFolderOutStream;
CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream);
const NHeader::CFolder &folder = m_Folders[realFolderIndex];
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;
switch(folder.GetCompressionMethod())
{
case NHeader::NCompressionMethodMajor::kNone:
{
if(storeDecoderSpec == 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;
}
break;
}
case NHeader::NCompressionMethodMajor::kMSZip:
{
if(lzxDecoderSpec == NULL)
{
msZipDecoderSpec = new NMSZip::CDecoder;
msZipDecoder = msZipDecoderSpec;
}
try
{
msZipDecoderSpec->SetParams(reservedSize, folder.NumDataBlocks);
RINOK(msZipDecoder->Code(m_Stream, outStream,
NULL, &totalFolderUnPacked, compressProgress));
}
catch(...)
{
RINOK(cabFolderOutStream->FlushCorrupted());
continue;
}
break;
}
case NHeader::NCompressionMethodMajor::kLZX:
{
if(lzxDecoderSpec == NULL)
{
lzxDecoderSpec = new NLZX::CDecoder;
lzxDecoder = lzxDecoderSpec;
}
try
{
lzxDecoderSpec->SetParams(reservedSize, folder.NumDataBlocks,
folder.CompressionTypeMinor);
RINOK(lzxDecoder->Code(m_Stream, outStream,
NULL, &totalFolderUnPacked, compressProgress));
}
catch(...)
{
RINOK(cabFolderOutStream->FlushCorrupted());
continue;
}
break;
}
default:
RINOK(cabFolderOutStream->Unsupported());
// return E_FAIL;
}
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CHandler::GetNumberOfItems(UINT32 *numItems)
{
COM_TRY_BEGIN
*numItems = m_Files.Size();
return S_OK;
COM_TRY_END
}
}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -