xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/7z/7zExtract.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // 7zExtract.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../../C/7zCrc.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/ComTry.h"
8*f6dc9357SAndroid Build Coastguard Worker 
9*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ProgressUtils.h"
10*f6dc9357SAndroid Build Coastguard Worker 
11*f6dc9357SAndroid Build Coastguard Worker #include "7zDecode.h"
12*f6dc9357SAndroid Build Coastguard Worker #include "7zHandler.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker // EXTERN_g_ExternalCodecs
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
17*f6dc9357SAndroid Build Coastguard Worker namespace N7z {
18*f6dc9357SAndroid Build Coastguard Worker 
19*f6dc9357SAndroid Build Coastguard Worker Z7_CLASS_IMP_COM_1(
20*f6dc9357SAndroid Build Coastguard Worker   CFolderOutStream
21*f6dc9357SAndroid Build Coastguard Worker   , ISequentialOutStream
22*f6dc9357SAndroid Build Coastguard Worker   /* , ICompressGetSubStreamSize */
23*f6dc9357SAndroid Build Coastguard Worker )
24*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> _stream;
25*f6dc9357SAndroid Build Coastguard Worker public:
26*f6dc9357SAndroid Build Coastguard Worker   bool TestMode;
27*f6dc9357SAndroid Build Coastguard Worker   bool CheckCrc;
28*f6dc9357SAndroid Build Coastguard Worker private:
29*f6dc9357SAndroid Build Coastguard Worker   bool _fileIsOpen;
30*f6dc9357SAndroid Build Coastguard Worker   bool _calcCrc;
31*f6dc9357SAndroid Build Coastguard Worker   UInt32 _crc;
32*f6dc9357SAndroid Build Coastguard Worker   UInt64 _rem;
33*f6dc9357SAndroid Build Coastguard Worker 
34*f6dc9357SAndroid Build Coastguard Worker   const UInt32 *_indexes;
35*f6dc9357SAndroid Build Coastguard Worker   // unsigned _startIndex;
36*f6dc9357SAndroid Build Coastguard Worker   unsigned _numFiles;
37*f6dc9357SAndroid Build Coastguard Worker   unsigned _fileIndex;
38*f6dc9357SAndroid Build Coastguard Worker 
39*f6dc9357SAndroid Build Coastguard Worker   HRESULT OpenFile(bool isCorrupted = false);
40*f6dc9357SAndroid Build Coastguard Worker   HRESULT CloseFile_and_SetResult(Int32 res);
41*f6dc9357SAndroid Build Coastguard Worker   HRESULT CloseFile();
42*f6dc9357SAndroid Build Coastguard Worker   HRESULT ProcessEmptyFiles();
43*f6dc9357SAndroid Build Coastguard Worker 
44*f6dc9357SAndroid Build Coastguard Worker public:
45*f6dc9357SAndroid Build Coastguard Worker   const CDbEx *_db;
46*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveExtractCallback> ExtractCallback;
47*f6dc9357SAndroid Build Coastguard Worker 
48*f6dc9357SAndroid Build Coastguard Worker   bool ExtraWriteWasCut;
49*f6dc9357SAndroid Build Coastguard Worker 
50*f6dc9357SAndroid Build Coastguard Worker   CFolderOutStream():
51*f6dc9357SAndroid Build Coastguard Worker       TestMode(false),
52*f6dc9357SAndroid Build Coastguard Worker       CheckCrc(true)
53*f6dc9357SAndroid Build Coastguard Worker       {}
54*f6dc9357SAndroid Build Coastguard Worker 
55*f6dc9357SAndroid Build Coastguard Worker   HRESULT Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles);
56*f6dc9357SAndroid Build Coastguard Worker   HRESULT FlushCorrupted(Int32 callbackOperationResult);
57*f6dc9357SAndroid Build Coastguard Worker 
58*f6dc9357SAndroid Build Coastguard Worker   bool WasWritingFinished() const { return _numFiles == 0; }
59*f6dc9357SAndroid Build Coastguard Worker };
60*f6dc9357SAndroid Build Coastguard Worker 
61*f6dc9357SAndroid Build Coastguard Worker 
62*f6dc9357SAndroid Build Coastguard Worker HRESULT CFolderOutStream::Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles)
63*f6dc9357SAndroid Build Coastguard Worker {
64*f6dc9357SAndroid Build Coastguard Worker   // _startIndex = startIndex;
65*f6dc9357SAndroid Build Coastguard Worker   _fileIndex = startIndex;
66*f6dc9357SAndroid Build Coastguard Worker   _indexes = indexes;
67*f6dc9357SAndroid Build Coastguard Worker   _numFiles = numFiles;
68*f6dc9357SAndroid Build Coastguard Worker 
69*f6dc9357SAndroid Build Coastguard Worker   _fileIsOpen = false;
70*f6dc9357SAndroid Build Coastguard Worker   ExtraWriteWasCut = false;
71*f6dc9357SAndroid Build Coastguard Worker 
72*f6dc9357SAndroid Build Coastguard Worker   return ProcessEmptyFiles();
73*f6dc9357SAndroid Build Coastguard Worker }
74*f6dc9357SAndroid Build Coastguard Worker 
75*f6dc9357SAndroid Build Coastguard Worker HRESULT CFolderOutStream::OpenFile(bool isCorrupted)
76*f6dc9357SAndroid Build Coastguard Worker {
77*f6dc9357SAndroid Build Coastguard Worker   const CFileItem &fi = _db->Files[_fileIndex];
78*f6dc9357SAndroid Build Coastguard Worker   const UInt32 nextFileIndex = (_indexes ? *_indexes : _fileIndex);
79*f6dc9357SAndroid Build Coastguard Worker   Int32 askMode = (_fileIndex == nextFileIndex) ? TestMode ?
80*f6dc9357SAndroid Build Coastguard Worker       NExtract::NAskMode::kTest :
81*f6dc9357SAndroid Build Coastguard Worker       NExtract::NAskMode::kExtract :
82*f6dc9357SAndroid Build Coastguard Worker       NExtract::NAskMode::kSkip;
83*f6dc9357SAndroid Build Coastguard Worker 
84*f6dc9357SAndroid Build Coastguard Worker   if (isCorrupted
85*f6dc9357SAndroid Build Coastguard Worker       && askMode == NExtract::NAskMode::kExtract
86*f6dc9357SAndroid Build Coastguard Worker       && !_db->IsItemAnti(_fileIndex)
87*f6dc9357SAndroid Build Coastguard Worker       && !fi.IsDir)
88*f6dc9357SAndroid Build Coastguard Worker     askMode = NExtract::NAskMode::kTest;
89*f6dc9357SAndroid Build Coastguard Worker 
90*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> realOutStream;
91*f6dc9357SAndroid Build Coastguard Worker   RINOK(ExtractCallback->GetStream(_fileIndex, &realOutStream, askMode))
92*f6dc9357SAndroid Build Coastguard Worker 
93*f6dc9357SAndroid Build Coastguard Worker   _stream = realOutStream;
94*f6dc9357SAndroid Build Coastguard Worker   _crc = CRC_INIT_VAL;
95*f6dc9357SAndroid Build Coastguard Worker   _calcCrc = (CheckCrc && fi.CrcDefined && !fi.IsDir);
96*f6dc9357SAndroid Build Coastguard Worker 
97*f6dc9357SAndroid Build Coastguard Worker   _fileIsOpen = true;
98*f6dc9357SAndroid Build Coastguard Worker   _rem = fi.Size;
99*f6dc9357SAndroid Build Coastguard Worker 
100*f6dc9357SAndroid Build Coastguard Worker   if (askMode == NExtract::NAskMode::kExtract
101*f6dc9357SAndroid Build Coastguard Worker       && !realOutStream
102*f6dc9357SAndroid Build Coastguard Worker       && !_db->IsItemAnti(_fileIndex)
103*f6dc9357SAndroid Build Coastguard Worker       && !fi.IsDir)
104*f6dc9357SAndroid Build Coastguard Worker     askMode = NExtract::NAskMode::kSkip;
105*f6dc9357SAndroid Build Coastguard Worker   return ExtractCallback->PrepareOperation(askMode);
106*f6dc9357SAndroid Build Coastguard Worker }
107*f6dc9357SAndroid Build Coastguard Worker 
108*f6dc9357SAndroid Build Coastguard Worker HRESULT CFolderOutStream::CloseFile_and_SetResult(Int32 res)
109*f6dc9357SAndroid Build Coastguard Worker {
110*f6dc9357SAndroid Build Coastguard Worker   _stream.Release();
111*f6dc9357SAndroid Build Coastguard Worker   _fileIsOpen = false;
112*f6dc9357SAndroid Build Coastguard Worker 
113*f6dc9357SAndroid Build Coastguard Worker   if (!_indexes)
114*f6dc9357SAndroid Build Coastguard Worker     _numFiles--;
115*f6dc9357SAndroid Build Coastguard Worker   else if (*_indexes == _fileIndex)
116*f6dc9357SAndroid Build Coastguard Worker   {
117*f6dc9357SAndroid Build Coastguard Worker     _indexes++;
118*f6dc9357SAndroid Build Coastguard Worker     _numFiles--;
119*f6dc9357SAndroid Build Coastguard Worker   }
120*f6dc9357SAndroid Build Coastguard Worker 
121*f6dc9357SAndroid Build Coastguard Worker   _fileIndex++;
122*f6dc9357SAndroid Build Coastguard Worker   return ExtractCallback->SetOperationResult(res);
123*f6dc9357SAndroid Build Coastguard Worker }
124*f6dc9357SAndroid Build Coastguard Worker 
125*f6dc9357SAndroid Build Coastguard Worker HRESULT CFolderOutStream::CloseFile()
126*f6dc9357SAndroid Build Coastguard Worker {
127*f6dc9357SAndroid Build Coastguard Worker   const CFileItem &fi = _db->Files[_fileIndex];
128*f6dc9357SAndroid Build Coastguard Worker   return CloseFile_and_SetResult((!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) ?
129*f6dc9357SAndroid Build Coastguard Worker       NExtract::NOperationResult::kOK :
130*f6dc9357SAndroid Build Coastguard Worker       NExtract::NOperationResult::kCRCError);
131*f6dc9357SAndroid Build Coastguard Worker }
132*f6dc9357SAndroid Build Coastguard Worker 
133*f6dc9357SAndroid Build Coastguard Worker HRESULT CFolderOutStream::ProcessEmptyFiles()
134*f6dc9357SAndroid Build Coastguard Worker {
135*f6dc9357SAndroid Build Coastguard Worker   while (_numFiles != 0 && _db->Files[_fileIndex].Size == 0)
136*f6dc9357SAndroid Build Coastguard Worker   {
137*f6dc9357SAndroid Build Coastguard Worker     RINOK(OpenFile())
138*f6dc9357SAndroid Build Coastguard Worker     RINOK(CloseFile())
139*f6dc9357SAndroid Build Coastguard Worker   }
140*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
141*f6dc9357SAndroid Build Coastguard Worker }
142*f6dc9357SAndroid Build Coastguard Worker 
143*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
144*f6dc9357SAndroid Build Coastguard Worker {
145*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
146*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
147*f6dc9357SAndroid Build Coastguard Worker 
148*f6dc9357SAndroid Build Coastguard Worker   while (size != 0)
149*f6dc9357SAndroid Build Coastguard Worker   {
150*f6dc9357SAndroid Build Coastguard Worker     if (_fileIsOpen)
151*f6dc9357SAndroid Build Coastguard Worker     {
152*f6dc9357SAndroid Build Coastguard Worker       UInt32 cur = (size < _rem ? size : (UInt32)_rem);
153*f6dc9357SAndroid Build Coastguard Worker       if (_calcCrc)
154*f6dc9357SAndroid Build Coastguard Worker       {
155*f6dc9357SAndroid Build Coastguard Worker         const UInt32 k_Step = (UInt32)1 << 20;
156*f6dc9357SAndroid Build Coastguard Worker         if (cur > k_Step)
157*f6dc9357SAndroid Build Coastguard Worker           cur = k_Step;
158*f6dc9357SAndroid Build Coastguard Worker       }
159*f6dc9357SAndroid Build Coastguard Worker       HRESULT result = S_OK;
160*f6dc9357SAndroid Build Coastguard Worker       if (_stream)
161*f6dc9357SAndroid Build Coastguard Worker         result = _stream->Write(data, cur, &cur);
162*f6dc9357SAndroid Build Coastguard Worker       if (_calcCrc)
163*f6dc9357SAndroid Build Coastguard Worker         _crc = CrcUpdate(_crc, data, cur);
164*f6dc9357SAndroid Build Coastguard Worker       if (processedSize)
165*f6dc9357SAndroid Build Coastguard Worker         *processedSize += cur;
166*f6dc9357SAndroid Build Coastguard Worker       data = (const Byte *)data + cur;
167*f6dc9357SAndroid Build Coastguard Worker       size -= cur;
168*f6dc9357SAndroid Build Coastguard Worker       _rem -= cur;
169*f6dc9357SAndroid Build Coastguard Worker       if (_rem == 0)
170*f6dc9357SAndroid Build Coastguard Worker       {
171*f6dc9357SAndroid Build Coastguard Worker         RINOK(CloseFile())
172*f6dc9357SAndroid Build Coastguard Worker         RINOK(ProcessEmptyFiles())
173*f6dc9357SAndroid Build Coastguard Worker       }
174*f6dc9357SAndroid Build Coastguard Worker       RINOK(result)
175*f6dc9357SAndroid Build Coastguard Worker       if (cur == 0)
176*f6dc9357SAndroid Build Coastguard Worker         break;
177*f6dc9357SAndroid Build Coastguard Worker       continue;
178*f6dc9357SAndroid Build Coastguard Worker     }
179*f6dc9357SAndroid Build Coastguard Worker 
180*f6dc9357SAndroid Build Coastguard Worker     RINOK(ProcessEmptyFiles())
181*f6dc9357SAndroid Build Coastguard Worker     if (_numFiles == 0)
182*f6dc9357SAndroid Build Coastguard Worker     {
183*f6dc9357SAndroid Build Coastguard Worker       // we support partial extracting
184*f6dc9357SAndroid Build Coastguard Worker       /*
185*f6dc9357SAndroid Build Coastguard Worker       if (processedSize)
186*f6dc9357SAndroid Build Coastguard Worker         *processedSize += size;
187*f6dc9357SAndroid Build Coastguard Worker       break;
188*f6dc9357SAndroid Build Coastguard Worker       */
189*f6dc9357SAndroid Build Coastguard Worker       ExtraWriteWasCut = true;
190*f6dc9357SAndroid Build Coastguard Worker       // return S_FALSE;
191*f6dc9357SAndroid Build Coastguard Worker       return k_My_HRESULT_WritingWasCut;
192*f6dc9357SAndroid Build Coastguard Worker     }
193*f6dc9357SAndroid Build Coastguard Worker     RINOK(OpenFile())
194*f6dc9357SAndroid Build Coastguard Worker   }
195*f6dc9357SAndroid Build Coastguard Worker 
196*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
197*f6dc9357SAndroid Build Coastguard Worker }
198*f6dc9357SAndroid Build Coastguard Worker 
199*f6dc9357SAndroid Build Coastguard Worker HRESULT CFolderOutStream::FlushCorrupted(Int32 callbackOperationResult)
200*f6dc9357SAndroid Build Coastguard Worker {
201*f6dc9357SAndroid Build Coastguard Worker   while (_numFiles != 0)
202*f6dc9357SAndroid Build Coastguard Worker   {
203*f6dc9357SAndroid Build Coastguard Worker     if (_fileIsOpen)
204*f6dc9357SAndroid Build Coastguard Worker     {
205*f6dc9357SAndroid Build Coastguard Worker       RINOK(CloseFile_and_SetResult(callbackOperationResult))
206*f6dc9357SAndroid Build Coastguard Worker     }
207*f6dc9357SAndroid Build Coastguard Worker     else
208*f6dc9357SAndroid Build Coastguard Worker     {
209*f6dc9357SAndroid Build Coastguard Worker       RINOK(OpenFile(true))
210*f6dc9357SAndroid Build Coastguard Worker     }
211*f6dc9357SAndroid Build Coastguard Worker   }
212*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
213*f6dc9357SAndroid Build Coastguard Worker }
214*f6dc9357SAndroid Build Coastguard Worker 
215*f6dc9357SAndroid Build Coastguard Worker /*
216*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value))
217*f6dc9357SAndroid Build Coastguard Worker {
218*f6dc9357SAndroid Build Coastguard Worker   *value = 0;
219*f6dc9357SAndroid Build Coastguard Worker   // const unsigned numFiles_Original = _numFiles + _fileIndex - _startIndex;
220*f6dc9357SAndroid Build Coastguard Worker   const unsigned numFiles_Original = _numFiles;
221*f6dc9357SAndroid Build Coastguard Worker   if (subStream >= numFiles_Original)
222*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE; // E_FAIL;
223*f6dc9357SAndroid Build Coastguard Worker   *value = _db->Files[_startIndex + (unsigned)subStream].Size;
224*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
225*f6dc9357SAndroid Build Coastguard Worker }
226*f6dc9357SAndroid Build Coastguard Worker */
227*f6dc9357SAndroid Build Coastguard Worker 
228*f6dc9357SAndroid Build Coastguard Worker 
229*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
230*f6dc9357SAndroid Build Coastguard Worker     Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec))
231*f6dc9357SAndroid Build Coastguard Worker {
232*f6dc9357SAndroid Build Coastguard Worker   // for GCC
233*f6dc9357SAndroid Build Coastguard Worker   // CFolderOutStream *folderOutStream = new CFolderOutStream;
234*f6dc9357SAndroid Build Coastguard Worker   // CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
235*f6dc9357SAndroid Build Coastguard Worker 
236*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
237*f6dc9357SAndroid Build Coastguard Worker 
238*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
239*f6dc9357SAndroid Build Coastguard Worker 
240*f6dc9357SAndroid Build Coastguard Worker   UInt64 importantTotalUnpacked = 0;
241*f6dc9357SAndroid Build Coastguard Worker 
242*f6dc9357SAndroid Build Coastguard Worker   // numItems = (UInt32)(Int32)-1;
243*f6dc9357SAndroid Build Coastguard Worker 
244*f6dc9357SAndroid Build Coastguard Worker   const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
245*f6dc9357SAndroid Build Coastguard Worker   if (allFilesMode)
246*f6dc9357SAndroid Build Coastguard Worker     numItems = _db.Files.Size();
247*f6dc9357SAndroid Build Coastguard Worker 
248*f6dc9357SAndroid Build Coastguard Worker   if (numItems == 0)
249*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
250*f6dc9357SAndroid Build Coastguard Worker 
251*f6dc9357SAndroid Build Coastguard Worker   {
252*f6dc9357SAndroid Build Coastguard Worker     CNum prevFolder = kNumNoIndex;
253*f6dc9357SAndroid Build Coastguard Worker     UInt32 nextFile = 0;
254*f6dc9357SAndroid Build Coastguard Worker 
255*f6dc9357SAndroid Build Coastguard Worker     UInt32 i;
256*f6dc9357SAndroid Build Coastguard Worker 
257*f6dc9357SAndroid Build Coastguard Worker     for (i = 0; i < numItems; i++)
258*f6dc9357SAndroid Build Coastguard Worker     {
259*f6dc9357SAndroid Build Coastguard Worker       const UInt32 fileIndex = allFilesMode ? i : indices[i];
260*f6dc9357SAndroid Build Coastguard Worker       const CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
261*f6dc9357SAndroid Build Coastguard Worker       if (folderIndex == kNumNoIndex)
262*f6dc9357SAndroid Build Coastguard Worker         continue;
263*f6dc9357SAndroid Build Coastguard Worker       if (folderIndex != prevFolder || fileIndex < nextFile)
264*f6dc9357SAndroid Build Coastguard Worker         nextFile = _db.FolderStartFileIndex[folderIndex];
265*f6dc9357SAndroid Build Coastguard Worker       for (CNum index = nextFile; index <= fileIndex; index++)
266*f6dc9357SAndroid Build Coastguard Worker         importantTotalUnpacked += _db.Files[index].Size;
267*f6dc9357SAndroid Build Coastguard Worker       nextFile = fileIndex + 1;
268*f6dc9357SAndroid Build Coastguard Worker       prevFolder = folderIndex;
269*f6dc9357SAndroid Build Coastguard Worker     }
270*f6dc9357SAndroid Build Coastguard Worker   }
271*f6dc9357SAndroid Build Coastguard Worker 
272*f6dc9357SAndroid Build Coastguard Worker   RINOK(extractCallback->SetTotal(importantTotalUnpacked))
273*f6dc9357SAndroid Build Coastguard Worker 
274*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> lps;
275*f6dc9357SAndroid Build Coastguard Worker   lps->Init(extractCallback, false);
276*f6dc9357SAndroid Build Coastguard Worker 
277*f6dc9357SAndroid Build Coastguard Worker   CDecoder decoder(
278*f6dc9357SAndroid Build Coastguard Worker     #if !defined(USE_MIXER_MT)
279*f6dc9357SAndroid Build Coastguard Worker       false
280*f6dc9357SAndroid Build Coastguard Worker     #elif !defined(USE_MIXER_ST)
281*f6dc9357SAndroid Build Coastguard Worker       true
282*f6dc9357SAndroid Build Coastguard Worker     #elif !defined(Z7_7Z_SET_PROPERTIES)
283*f6dc9357SAndroid Build Coastguard Worker       #ifdef Z7_ST
284*f6dc9357SAndroid Build Coastguard Worker         false
285*f6dc9357SAndroid Build Coastguard Worker       #else
286*f6dc9357SAndroid Build Coastguard Worker         true
287*f6dc9357SAndroid Build Coastguard Worker       #endif
288*f6dc9357SAndroid Build Coastguard Worker     #else
289*f6dc9357SAndroid Build Coastguard Worker       _useMultiThreadMixer
290*f6dc9357SAndroid Build Coastguard Worker     #endif
291*f6dc9357SAndroid Build Coastguard Worker     );
292*f6dc9357SAndroid Build Coastguard Worker 
293*f6dc9357SAndroid Build Coastguard Worker   UInt64 curPacked, curUnpacked;
294*f6dc9357SAndroid Build Coastguard Worker 
295*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<IArchiveExtractCallbackMessage2> callbackMessage;
296*f6dc9357SAndroid Build Coastguard Worker   extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage2, &callbackMessage);
297*f6dc9357SAndroid Build Coastguard Worker 
298*f6dc9357SAndroid Build Coastguard Worker   CFolderOutStream *folderOutStream = new CFolderOutStream;
299*f6dc9357SAndroid Build Coastguard Worker   CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
300*f6dc9357SAndroid Build Coastguard Worker 
301*f6dc9357SAndroid Build Coastguard Worker   folderOutStream->_db = &_db;
302*f6dc9357SAndroid Build Coastguard Worker   folderOutStream->ExtractCallback = extractCallback;
303*f6dc9357SAndroid Build Coastguard Worker   folderOutStream->TestMode = (testModeSpec != 0);
304*f6dc9357SAndroid Build Coastguard Worker   folderOutStream->CheckCrc = (_crcSize != 0);
305*f6dc9357SAndroid Build Coastguard Worker 
306*f6dc9357SAndroid Build Coastguard Worker   for (UInt32 i = 0;; lps->OutSize += curUnpacked, lps->InSize += curPacked)
307*f6dc9357SAndroid Build Coastguard Worker   {
308*f6dc9357SAndroid Build Coastguard Worker     RINOK(lps->SetCur())
309*f6dc9357SAndroid Build Coastguard Worker 
310*f6dc9357SAndroid Build Coastguard Worker     if (i >= numItems)
311*f6dc9357SAndroid Build Coastguard Worker       break;
312*f6dc9357SAndroid Build Coastguard Worker 
313*f6dc9357SAndroid Build Coastguard Worker     curUnpacked = 0;
314*f6dc9357SAndroid Build Coastguard Worker     curPacked = 0;
315*f6dc9357SAndroid Build Coastguard Worker 
316*f6dc9357SAndroid Build Coastguard Worker     UInt32 fileIndex = allFilesMode ? i : indices[i];
317*f6dc9357SAndroid Build Coastguard Worker     const CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
318*f6dc9357SAndroid Build Coastguard Worker 
319*f6dc9357SAndroid Build Coastguard Worker     UInt32 numSolidFiles = 1;
320*f6dc9357SAndroid Build Coastguard Worker 
321*f6dc9357SAndroid Build Coastguard Worker     if (folderIndex != kNumNoIndex)
322*f6dc9357SAndroid Build Coastguard Worker     {
323*f6dc9357SAndroid Build Coastguard Worker       curPacked = _db.GetFolderFullPackSize(folderIndex);
324*f6dc9357SAndroid Build Coastguard Worker       UInt32 nextFile = fileIndex + 1;
325*f6dc9357SAndroid Build Coastguard Worker       fileIndex = _db.FolderStartFileIndex[folderIndex];
326*f6dc9357SAndroid Build Coastguard Worker       UInt32 k;
327*f6dc9357SAndroid Build Coastguard Worker 
328*f6dc9357SAndroid Build Coastguard Worker       for (k = i + 1; k < numItems; k++)
329*f6dc9357SAndroid Build Coastguard Worker       {
330*f6dc9357SAndroid Build Coastguard Worker         const UInt32 fileIndex2 = allFilesMode ? k : indices[k];
331*f6dc9357SAndroid Build Coastguard Worker         if (_db.FileIndexToFolderIndexMap[fileIndex2] != folderIndex
332*f6dc9357SAndroid Build Coastguard Worker             || fileIndex2 < nextFile)
333*f6dc9357SAndroid Build Coastguard Worker           break;
334*f6dc9357SAndroid Build Coastguard Worker         nextFile = fileIndex2 + 1;
335*f6dc9357SAndroid Build Coastguard Worker       }
336*f6dc9357SAndroid Build Coastguard Worker 
337*f6dc9357SAndroid Build Coastguard Worker       numSolidFiles = k - i;
338*f6dc9357SAndroid Build Coastguard Worker 
339*f6dc9357SAndroid Build Coastguard Worker       for (k = fileIndex; k < nextFile; k++)
340*f6dc9357SAndroid Build Coastguard Worker         curUnpacked += _db.Files[k].Size;
341*f6dc9357SAndroid Build Coastguard Worker     }
342*f6dc9357SAndroid Build Coastguard Worker 
343*f6dc9357SAndroid Build Coastguard Worker     {
344*f6dc9357SAndroid Build Coastguard Worker       const HRESULT result = folderOutStream->Init(fileIndex,
345*f6dc9357SAndroid Build Coastguard Worker           allFilesMode ? NULL : indices + i,
346*f6dc9357SAndroid Build Coastguard Worker           numSolidFiles);
347*f6dc9357SAndroid Build Coastguard Worker 
348*f6dc9357SAndroid Build Coastguard Worker       i += numSolidFiles;
349*f6dc9357SAndroid Build Coastguard Worker 
350*f6dc9357SAndroid Build Coastguard Worker       RINOK(result)
351*f6dc9357SAndroid Build Coastguard Worker     }
352*f6dc9357SAndroid Build Coastguard Worker 
353*f6dc9357SAndroid Build Coastguard Worker     if (folderOutStream->WasWritingFinished())
354*f6dc9357SAndroid Build Coastguard Worker     {
355*f6dc9357SAndroid Build Coastguard Worker       // for debug: to test zero size stream unpacking
356*f6dc9357SAndroid Build Coastguard Worker       // if (folderIndex == kNumNoIndex)  // enable this check for debug
357*f6dc9357SAndroid Build Coastguard Worker       continue;
358*f6dc9357SAndroid Build Coastguard Worker     }
359*f6dc9357SAndroid Build Coastguard Worker 
360*f6dc9357SAndroid Build Coastguard Worker     if (folderIndex == kNumNoIndex)
361*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
362*f6dc9357SAndroid Build Coastguard Worker 
363*f6dc9357SAndroid Build Coastguard Worker     #ifndef Z7_NO_CRYPTO
364*f6dc9357SAndroid Build Coastguard Worker     CMyComPtr<ICryptoGetTextPassword> getTextPassword;
365*f6dc9357SAndroid Build Coastguard Worker     if (extractCallback)
366*f6dc9357SAndroid Build Coastguard Worker       extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
367*f6dc9357SAndroid Build Coastguard Worker     #endif
368*f6dc9357SAndroid Build Coastguard Worker 
369*f6dc9357SAndroid Build Coastguard Worker     try
370*f6dc9357SAndroid Build Coastguard Worker     {
371*f6dc9357SAndroid Build Coastguard Worker       #ifndef Z7_NO_CRYPTO
372*f6dc9357SAndroid Build Coastguard Worker         bool isEncrypted = false;
373*f6dc9357SAndroid Build Coastguard Worker         bool passwordIsDefined = false;
374*f6dc9357SAndroid Build Coastguard Worker         UString_Wipe password;
375*f6dc9357SAndroid Build Coastguard Worker       #endif
376*f6dc9357SAndroid Build Coastguard Worker 
377*f6dc9357SAndroid Build Coastguard Worker       bool dataAfterEnd_Error = false;
378*f6dc9357SAndroid Build Coastguard Worker 
379*f6dc9357SAndroid Build Coastguard Worker       const HRESULT result = decoder.Decode(
380*f6dc9357SAndroid Build Coastguard Worker           EXTERNAL_CODECS_VARS
381*f6dc9357SAndroid Build Coastguard Worker           _inStream,
382*f6dc9357SAndroid Build Coastguard Worker           _db.ArcInfo.DataStartPosition,
383*f6dc9357SAndroid Build Coastguard Worker           _db, folderIndex,
384*f6dc9357SAndroid Build Coastguard Worker           &curUnpacked,
385*f6dc9357SAndroid Build Coastguard Worker 
386*f6dc9357SAndroid Build Coastguard Worker           outStream,
387*f6dc9357SAndroid Build Coastguard Worker           lps,
388*f6dc9357SAndroid Build Coastguard Worker           NULL // *inStreamMainRes
389*f6dc9357SAndroid Build Coastguard Worker           , dataAfterEnd_Error
390*f6dc9357SAndroid Build Coastguard Worker 
391*f6dc9357SAndroid Build Coastguard Worker           Z7_7Z_DECODER_CRYPRO_VARS
392*f6dc9357SAndroid Build Coastguard Worker           #if !defined(Z7_ST)
393*f6dc9357SAndroid Build Coastguard Worker             , true, _numThreads, _memUsage_Decompress
394*f6dc9357SAndroid Build Coastguard Worker           #endif
395*f6dc9357SAndroid Build Coastguard Worker           );
396*f6dc9357SAndroid Build Coastguard Worker 
397*f6dc9357SAndroid Build Coastguard Worker       if (result == S_FALSE || result == E_NOTIMPL || dataAfterEnd_Error)
398*f6dc9357SAndroid Build Coastguard Worker       {
399*f6dc9357SAndroid Build Coastguard Worker         const bool wasFinished = folderOutStream->WasWritingFinished();
400*f6dc9357SAndroid Build Coastguard Worker 
401*f6dc9357SAndroid Build Coastguard Worker         int resOp = NExtract::NOperationResult::kDataError;
402*f6dc9357SAndroid Build Coastguard Worker 
403*f6dc9357SAndroid Build Coastguard Worker         if (result != S_FALSE)
404*f6dc9357SAndroid Build Coastguard Worker         {
405*f6dc9357SAndroid Build Coastguard Worker           if (result == E_NOTIMPL)
406*f6dc9357SAndroid Build Coastguard Worker             resOp = NExtract::NOperationResult::kUnsupportedMethod;
407*f6dc9357SAndroid Build Coastguard Worker           else if (wasFinished && dataAfterEnd_Error)
408*f6dc9357SAndroid Build Coastguard Worker             resOp = NExtract::NOperationResult::kDataAfterEnd;
409*f6dc9357SAndroid Build Coastguard Worker         }
410*f6dc9357SAndroid Build Coastguard Worker 
411*f6dc9357SAndroid Build Coastguard Worker         RINOK(folderOutStream->FlushCorrupted(resOp))
412*f6dc9357SAndroid Build Coastguard Worker 
413*f6dc9357SAndroid Build Coastguard Worker         if (wasFinished)
414*f6dc9357SAndroid Build Coastguard Worker         {
415*f6dc9357SAndroid Build Coastguard Worker           // we don't show error, if it's after required files
416*f6dc9357SAndroid Build Coastguard Worker           if (/* !folderOutStream->ExtraWriteWasCut && */ callbackMessage)
417*f6dc9357SAndroid Build Coastguard Worker           {
418*f6dc9357SAndroid Build Coastguard Worker             RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, resOp))
419*f6dc9357SAndroid Build Coastguard Worker           }
420*f6dc9357SAndroid Build Coastguard Worker         }
421*f6dc9357SAndroid Build Coastguard Worker         continue;
422*f6dc9357SAndroid Build Coastguard Worker       }
423*f6dc9357SAndroid Build Coastguard Worker 
424*f6dc9357SAndroid Build Coastguard Worker       if (result != S_OK)
425*f6dc9357SAndroid Build Coastguard Worker         return result;
426*f6dc9357SAndroid Build Coastguard Worker 
427*f6dc9357SAndroid Build Coastguard Worker       RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError))
428*f6dc9357SAndroid Build Coastguard Worker       continue;
429*f6dc9357SAndroid Build Coastguard Worker     }
430*f6dc9357SAndroid Build Coastguard Worker     catch(...)
431*f6dc9357SAndroid Build Coastguard Worker     {
432*f6dc9357SAndroid Build Coastguard Worker       RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError))
433*f6dc9357SAndroid Build Coastguard Worker       // continue;
434*f6dc9357SAndroid Build Coastguard Worker       // return E_FAIL;
435*f6dc9357SAndroid Build Coastguard Worker       throw;
436*f6dc9357SAndroid Build Coastguard Worker     }
437*f6dc9357SAndroid Build Coastguard Worker   }
438*f6dc9357SAndroid Build Coastguard Worker 
439*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
440*f6dc9357SAndroid Build Coastguard Worker 
441*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
442*f6dc9357SAndroid Build Coastguard Worker }
443*f6dc9357SAndroid Build Coastguard Worker 
444*f6dc9357SAndroid Build Coastguard Worker }}
445