physfs/src/lzma/CPP/7zip/Archive/7z/7zFolderOutStream.cpp

166 lines
4.3 KiB
C++

// 7zFolderOutStream.cpp
#include "StdAfx.h"
#include "7zFolderOutStream.h"
namespace NArchive {
namespace N7z {
CFolderOutStream::CFolderOutStream()
{
_outStreamWithHashSpec = new COutStreamWithCRC;
_outStreamWithHash = _outStreamWithHashSpec;
}
HRESULT CFolderOutStream::Init(
const CArchiveDatabaseEx *archiveDatabase,
UInt32 ref2Offset,
UInt32 startIndex,
const CBoolVector *extractStatuses,
IArchiveExtractCallback *extractCallback,
bool testMode,
bool checkCrc)
{
_archiveDatabase = archiveDatabase;
_ref2Offset = ref2Offset;
_startIndex = startIndex;
_extractStatuses = extractStatuses;
_extractCallback = extractCallback;
_testMode = testMode;
_checkCrc = checkCrc;
_currentIndex = 0;
_fileIsOpen = false;
return WriteEmptyFiles();
}
HRESULT CFolderOutStream::OpenFile()
{
Int32 askMode;
if((*_extractStatuses)[_currentIndex])
askMode = _testMode ?
NArchive::NExtract::NAskMode::kTest :
NArchive::NExtract::NAskMode::kExtract;
else
askMode = NArchive::NExtract::NAskMode::kSkip;
CMyComPtr<ISequentialOutStream> realOutStream;
UInt32 index = _startIndex + _currentIndex;
RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
_outStreamWithHashSpec->SetStream(realOutStream);
_outStreamWithHashSpec->Init(_checkCrc);
if (askMode == NArchive::NExtract::NAskMode::kExtract &&
(!realOutStream))
{
const CFileItem &fileInfo = _archiveDatabase->Files[index];
if (!fileInfo.IsAnti && !fileInfo.IsDirectory)
askMode = NArchive::NExtract::NAskMode::kSkip;
}
return _extractCallback->PrepareOperation(askMode);
}
HRESULT CFolderOutStream::WriteEmptyFiles()
{
for(;_currentIndex < _extractStatuses->Size(); _currentIndex++)
{
UInt32 index = _startIndex + _currentIndex;
const CFileItem &fileInfo = _archiveDatabase->Files[index];
if (!fileInfo.IsAnti && !fileInfo.IsDirectory && fileInfo.UnPackSize != 0)
return S_OK;
RINOK(OpenFile());
RINOK(_extractCallback->SetOperationResult(
NArchive::NExtract::NOperationResult::kOK));
_outStreamWithHashSpec->ReleaseStream();
}
return S_OK;
}
STDMETHODIMP CFolderOutStream::Write(const void *data,
UInt32 size, UInt32 *processedSize)
{
UInt32 realProcessedSize = 0;
while(_currentIndex < _extractStatuses->Size())
{
if (_fileIsOpen)
{
UInt32 index = _startIndex + _currentIndex;
const CFileItem &fileInfo = _archiveDatabase->Files[index];
UInt64 fileSize = fileInfo.UnPackSize;
UInt32 numBytesToWrite = (UInt32)MyMin(fileSize - _filePos,
UInt64(size - realProcessedSize));
UInt32 processedSizeLocal;
RINOK(_outStreamWithHash->Write((const Byte *)data + realProcessedSize,
numBytesToWrite, &processedSizeLocal));
_filePos += processedSizeLocal;
realProcessedSize += processedSizeLocal;
if (_filePos == fileSize)
{
bool digestsAreEqual;
if (fileInfo.IsFileCRCDefined && _checkCrc)
digestsAreEqual = fileInfo.FileCRC == _outStreamWithHashSpec->GetCRC();
else
digestsAreEqual = true;
RINOK(_extractCallback->SetOperationResult(
digestsAreEqual ?
NArchive::NExtract::NOperationResult::kOK :
NArchive::NExtract::NOperationResult::kCRCError));
_outStreamWithHashSpec->ReleaseStream();
_fileIsOpen = false;
_currentIndex++;
}
if (realProcessedSize == size)
{
if (processedSize != NULL)
*processedSize = realProcessedSize;
return WriteEmptyFiles();
}
}
else
{
RINOK(OpenFile());
_fileIsOpen = true;
_filePos = 0;
}
}
if (processedSize != NULL)
*processedSize = size;
return S_OK;
}
HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
{
while(_currentIndex < _extractStatuses->Size())
{
if (_fileIsOpen)
{
RINOK(_extractCallback->SetOperationResult(resultEOperationResult));
_outStreamWithHashSpec->ReleaseStream();
_fileIsOpen = false;
_currentIndex++;
}
else
{
RINOK(OpenFile());
_fileIsOpen = true;
}
}
return S_OK;
}
HRESULT CFolderOutStream::WasWritingFinished()
{
if (_currentIndex == _extractStatuses->Size())
return S_OK;
return E_FAIL;
}
}}