// 7zFolderOutStream.cpp
#include "StdAfx.h"
#include "7zFolderOutStream.h"
namespace NArchive {
namespace N7z {
CFolderOutStream::CFolderOutStream()
{
_crcStreamSpec = new COutStreamWithCRC;
_crcStream = _crcStreamSpec;
}
HRESULT CFolderOutStream::Init(
const CDbEx *db,
UInt32 ref2Offset, UInt32 startIndex,
const CBoolVector *extractStatuses,
IArchiveExtractCallback *extractCallback,
bool testMode, bool checkCrc)
{
_db = db;
_ref2Offset = ref2Offset;
_startIndex = startIndex;
_extractStatuses = extractStatuses;
_extractCallback = extractCallback;
_testMode = testMode;
_checkCrc = checkCrc;
_currentIndex = 0;
_fileIsOpen = false;
return ProcessEmptyFiles();
}
HRESULT CFolderOutStream::OpenFile()
{
Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract) :
NExtract::NAskMode::kSkip;
CMyComPtr<ISequentialOutStream> realOutStream;
UInt32 index = _startIndex + _currentIndex;
RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode));
_crcStreamSpec->SetStream(realOutStream);
_crcStreamSpec->Init(_checkCrc);
_fileIsOpen = true;
const CFileItem &fi = _db->Files[index];
_rem = fi.Size;
if (askMode == NExtract::NAskMode::kExtract && !realOutStream &&
!_db->IsItemAnti(index) && !fi.IsDir)
askMode = NExtract::NAskMode::kSkip;
return _extractCallback->PrepareOperation(askMode);
}
HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res)
{
_crcStreamSpec->ReleaseStream();
_fileIsOpen = false;
_currentIndex++;
return _extractCallback->SetOperationResult(res);
}
HRESULT CFolderOutStream::CloseFileAndSetResult()
{
const CFileItem &fi = _db->Files[_startIndex + _currentIndex];
return CloseFileAndSetResult(
(fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ?
NExtract::NOperationResult::kOK :
NExtract::NOperationResult::kCRCError);
}
HRESULT CFolderOutStream::ProcessEmptyFiles()
{
while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
{
RINOK(OpenFile());
RINOK(CloseFileAndSetResult());
}
return S_OK;
}
STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize != NULL)
*processedSize = 0;
while (size != 0)
{
if (_fileIsOpen)
{
UInt32 cur = size < _rem ? size : (UInt32)_rem;
RINOK(_crcStream->Write(data, cur, &cur));
if (cur == 0)
break;
data = (const Byte *)data + cur;
size -= cur;
_rem -= cur;
if (processedSize != NULL)
*processedSize += cur;
if (_rem == 0)
{
RINOK(CloseFileAndSetResult());
RINOK(ProcessEmptyFiles());
continue;
}
}
else
{
RINOK(ProcessEmptyFiles());
if (_currentIndex == _extractStatuses->Size())
{
// we support partial extracting
if (processedSize != NULL)
*processedSize += size;
break;
}
RINOK(OpenFile());
}
}
return S_OK;
}
STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
{
*value = 0;
if ((int)subStream >= _extractStatuses->Size())
return S_FALSE;
*value = _db->Files[_startIndex + (int)subStream].Size;
return S_OK;
}
HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult)
{
while (_currentIndex < _extractStatuses->Size())
{
if (_fileIsOpen)
{
RINOK(CloseFileAndSetResult(resultEOperationResult));
}
else
{
RINOK(OpenFile());
}
}
return S_OK;
}
}}