1// 7zFolderOutStream.cpp 2 3#include "StdAfx.h" 4 5#include "7zFolderOutStream.h" 6 7namespace NArchive { 8namespace N7z { 9 10CFolderOutStream::CFolderOutStream() 11{ 12 _crcStreamSpec = new COutStreamWithCRC; 13 _crcStream = _crcStreamSpec; 14} 15 16HRESULT CFolderOutStream::Init( 17 const CDbEx *db, 18 UInt32 ref2Offset, UInt32 startIndex, 19 const CBoolVector *extractStatuses, 20 IArchiveExtractCallback *extractCallback, 21 bool testMode, bool checkCrc) 22{ 23 _db = db; 24 _ref2Offset = ref2Offset; 25 _startIndex = startIndex; 26 27 _extractStatuses = extractStatuses; 28 _extractCallback = extractCallback; 29 _testMode = testMode; 30 _checkCrc = checkCrc; 31 32 _currentIndex = 0; 33 _fileIsOpen = false; 34 return ProcessEmptyFiles(); 35} 36 37HRESULT CFolderOutStream::OpenFile() 38{ 39 Int32 askMode = ((*_extractStatuses)[_currentIndex]) ? (_testMode ? 40 NExtract::NAskMode::kTest : 41 NExtract::NAskMode::kExtract) : 42 NExtract::NAskMode::kSkip; 43 CMyComPtr<ISequentialOutStream> realOutStream; 44 UInt32 index = _startIndex + _currentIndex; 45 RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode)); 46 _crcStreamSpec->SetStream(realOutStream); 47 _crcStreamSpec->Init(_checkCrc); 48 _fileIsOpen = true; 49 const CFileItem &fi = _db->Files[index]; 50 _rem = fi.Size; 51 if (askMode == NExtract::NAskMode::kExtract && !realOutStream && 52 !_db->IsItemAnti(index) && !fi.IsDir) 53 askMode = NExtract::NAskMode::kSkip; 54 return _extractCallback->PrepareOperation(askMode); 55} 56 57HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res) 58{ 59 _crcStreamSpec->ReleaseStream(); 60 _fileIsOpen = false; 61 _currentIndex++; 62 return _extractCallback->SetOperationResult(res); 63} 64 65HRESULT CFolderOutStream::CloseFileAndSetResult() 66{ 67 const CFileItem &fi = _db->Files[_startIndex + _currentIndex]; 68 return CloseFileAndSetResult( 69 (fi.IsDir || !fi.CrcDefined || !_checkCrc || fi.Crc == _crcStreamSpec->GetCRC()) ? 70 NExtract::NOperationResult::kOK : 71 NExtract::NOperationResult::kCRCError); 72} 73 74HRESULT CFolderOutStream::ProcessEmptyFiles() 75{ 76 while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) 77 { 78 RINOK(OpenFile()); 79 RINOK(CloseFileAndSetResult()); 80 } 81 return S_OK; 82} 83 84STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 85{ 86 if (processedSize != NULL) 87 *processedSize = 0; 88 while (size != 0) 89 { 90 if (_fileIsOpen) 91 { 92 UInt32 cur = size < _rem ? size : (UInt32)_rem; 93 RINOK(_crcStream->Write(data, cur, &cur)); 94 if (cur == 0) 95 break; 96 data = (const Byte *)data + cur; 97 size -= cur; 98 _rem -= cur; 99 if (processedSize != NULL) 100 *processedSize += cur; 101 if (_rem == 0) 102 { 103 RINOK(CloseFileAndSetResult()); 104 RINOK(ProcessEmptyFiles()); 105 continue; 106 } 107 } 108 else 109 { 110 RINOK(ProcessEmptyFiles()); 111 if (_currentIndex == _extractStatuses->Size()) 112 { 113 // we support partial extracting 114 if (processedSize != NULL) 115 *processedSize += size; 116 break; 117 } 118 RINOK(OpenFile()); 119 } 120 } 121 return S_OK; 122} 123 124STDMETHODIMP CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value) 125{ 126 *value = 0; 127 if ((int)subStream >= _extractStatuses->Size()) 128 return S_FALSE; 129 *value = _db->Files[_startIndex + (int)subStream].Size; 130 return S_OK; 131} 132 133HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult) 134{ 135 while (_currentIndex < _extractStatuses->Size()) 136 { 137 if (_fileIsOpen) 138 { 139 RINOK(CloseFileAndSetResult(resultEOperationResult)); 140 } 141 else 142 { 143 RINOK(OpenFile()); 144 } 145 } 146 return S_OK; 147} 148 149}} 150