| // 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; | |
| } | |
| }} |