1 // 7zFolderOutStream.cpp
2
3 #include "StdAfx.h"
4
5 #include "7zFolderOutStream.h"
6
7 namespace NArchive {
8 namespace N7z {
9
CFolderOutStream()10 CFolderOutStream::CFolderOutStream()
11 {
12 _crcStreamSpec = new COutStreamWithCRC;
13 _crcStream = _crcStreamSpec;
14 }
15
Init(const CArchiveDatabaseEx * db,UInt32 ref2Offset,UInt32 startIndex,const CBoolVector * extractStatuses,IArchiveExtractCallback * extractCallback,bool testMode,bool checkCrc)16 HRESULT CFolderOutStream::Init(
17 const CArchiveDatabaseEx *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
OpenFile()37 HRESULT 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
CloseFileAndSetResult(Int32 res)57 HRESULT CFolderOutStream::CloseFileAndSetResult(Int32 res)
58 {
59 _crcStreamSpec->ReleaseStream();
60 _fileIsOpen = false;
61 _currentIndex++;
62 return _extractCallback->SetOperationResult(res);
63 }
64
CloseFileAndSetResult()65 HRESULT 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
ProcessEmptyFiles()74 HRESULT 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
Write(const void * data,UInt32 size,UInt32 * processedSize)84 STDMETHODIMP 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
GetSubStreamSize(UInt64 subStream,UInt64 * value)124 STDMETHODIMP 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
FlushCorrupted(Int32 resultEOperationResult)133 HRESULT 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