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