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 CDbEx * db,UInt32 ref2Offset,UInt32 startIndex,const CBoolVector * extractStatuses,IArchiveExtractCallback * extractCallback,bool testMode,bool checkCrc)16 HRESULT 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 
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