rlm@1
|
1 // 7zExtract.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 #include "7zHandler.h"
|
rlm@1
|
6 #include "7zFolderOutStream.h"
|
rlm@1
|
7 #include "7zDecode.h"
|
rlm@1
|
8 // #include "7z1Decode.h"
|
rlm@1
|
9
|
rlm@1
|
10 #include "../../../Common/ComTry.h"
|
rlm@1
|
11 #include "../../Common/StreamObjects.h"
|
rlm@1
|
12 #include "../../Common/ProgressUtils.h"
|
rlm@1
|
13 #include "../../Common/LimitedStreams.h"
|
rlm@1
|
14
|
rlm@1
|
15 namespace NArchive {
|
rlm@1
|
16 namespace N7z {
|
rlm@1
|
17
|
rlm@1
|
18 struct CExtractFolderInfo
|
rlm@1
|
19 {
|
rlm@1
|
20 #ifdef _7Z_VOL
|
rlm@1
|
21 int VolumeIndex;
|
rlm@1
|
22 #endif
|
rlm@1
|
23 CNum FileIndex;
|
rlm@1
|
24 CNum FolderIndex;
|
rlm@1
|
25 CBoolVector ExtractStatuses;
|
rlm@1
|
26 UInt64 UnpackSize;
|
rlm@1
|
27 CExtractFolderInfo(
|
rlm@1
|
28 #ifdef _7Z_VOL
|
rlm@1
|
29 int volumeIndex,
|
rlm@1
|
30 #endif
|
rlm@1
|
31 CNum fileIndex, CNum folderIndex):
|
rlm@1
|
32 #ifdef _7Z_VOL
|
rlm@1
|
33 VolumeIndex(volumeIndex),
|
rlm@1
|
34 #endif
|
rlm@1
|
35 FileIndex(fileIndex),
|
rlm@1
|
36 FolderIndex(folderIndex),
|
rlm@1
|
37 UnpackSize(0)
|
rlm@1
|
38 {
|
rlm@1
|
39 if (fileIndex != kNumNoIndex)
|
rlm@1
|
40 {
|
rlm@1
|
41 ExtractStatuses.Reserve(1);
|
rlm@1
|
42 ExtractStatuses.Add(true);
|
rlm@1
|
43 }
|
rlm@1
|
44 };
|
rlm@1
|
45 };
|
rlm@1
|
46
|
rlm@1
|
47 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
rlm@1
|
48 Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
|
rlm@1
|
49 {
|
rlm@1
|
50 COM_TRY_BEGIN
|
rlm@1
|
51 bool testMode = (testModeSpec != 0);
|
rlm@1
|
52 CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
|
rlm@1
|
53 UInt64 importantTotalUnpacked = 0;
|
rlm@1
|
54
|
rlm@1
|
55 bool allFilesMode = (numItems == UInt32(-1));
|
rlm@1
|
56 if (allFilesMode)
|
rlm@1
|
57 numItems =
|
rlm@1
|
58 #ifdef _7Z_VOL
|
rlm@1
|
59 _refs.Size();
|
rlm@1
|
60 #else
|
rlm@1
|
61 _db.Files.Size();
|
rlm@1
|
62 #endif
|
rlm@1
|
63
|
rlm@1
|
64 if(numItems == 0)
|
rlm@1
|
65 return S_OK;
|
rlm@1
|
66
|
rlm@1
|
67 /*
|
rlm@1
|
68 if(_volumes.Size() != 1)
|
rlm@1
|
69 return E_FAIL;
|
rlm@1
|
70 const CVolume &volume = _volumes.Front();
|
rlm@1
|
71 const CArchiveDatabaseEx &_db = volume.Database;
|
rlm@1
|
72 IInStream *_inStream = volume.Stream;
|
rlm@1
|
73 */
|
rlm@1
|
74
|
rlm@1
|
75 CObjectVector<CExtractFolderInfo> extractFolderInfoVector;
|
rlm@1
|
76 for(UInt32 ii = 0; ii < numItems; ii++)
|
rlm@1
|
77 {
|
rlm@1
|
78 // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex];
|
rlm@1
|
79 UInt32 ref2Index = allFilesMode ? ii : indices[ii];
|
rlm@1
|
80 // const CRef2 &ref2 = _refs[ref2Index];
|
rlm@1
|
81
|
rlm@1
|
82 // for(UInt32 ri = 0; ri < ref2.Refs.Size(); ri++)
|
rlm@1
|
83 {
|
rlm@1
|
84 #ifdef _7Z_VOL
|
rlm@1
|
85 // const CRef &ref = ref2.Refs[ri];
|
rlm@1
|
86 const CRef &ref = _refs[ref2Index];
|
rlm@1
|
87
|
rlm@1
|
88 int volumeIndex = ref.VolumeIndex;
|
rlm@1
|
89 const CVolume &volume = _volumes[volumeIndex];
|
rlm@1
|
90 const CArchiveDatabaseEx &db = volume.Database;
|
rlm@1
|
91 UInt32 fileIndex = ref.ItemIndex;
|
rlm@1
|
92 #else
|
rlm@1
|
93 const CArchiveDatabaseEx &db = _db;
|
rlm@1
|
94 UInt32 fileIndex = ref2Index;
|
rlm@1
|
95 #endif
|
rlm@1
|
96
|
rlm@1
|
97 CNum folderIndex = db.FileIndexToFolderIndexMap[fileIndex];
|
rlm@1
|
98 if (folderIndex == kNumNoIndex)
|
rlm@1
|
99 {
|
rlm@1
|
100 extractFolderInfoVector.Add(CExtractFolderInfo(
|
rlm@1
|
101 #ifdef _7Z_VOL
|
rlm@1
|
102 volumeIndex,
|
rlm@1
|
103 #endif
|
rlm@1
|
104 fileIndex, kNumNoIndex));
|
rlm@1
|
105 continue;
|
rlm@1
|
106 }
|
rlm@1
|
107 if (extractFolderInfoVector.IsEmpty() ||
|
rlm@1
|
108 folderIndex != extractFolderInfoVector.Back().FolderIndex
|
rlm@1
|
109 #ifdef _7Z_VOL
|
rlm@1
|
110 || volumeIndex != extractFolderInfoVector.Back().VolumeIndex
|
rlm@1
|
111 #endif
|
rlm@1
|
112 )
|
rlm@1
|
113 {
|
rlm@1
|
114 extractFolderInfoVector.Add(CExtractFolderInfo(
|
rlm@1
|
115 #ifdef _7Z_VOL
|
rlm@1
|
116 volumeIndex,
|
rlm@1
|
117 #endif
|
rlm@1
|
118 kNumNoIndex, folderIndex));
|
rlm@1
|
119 const CFolder &folderInfo = db.Folders[folderIndex];
|
rlm@1
|
120 UInt64 unpackSize = folderInfo.GetUnpackSize();
|
rlm@1
|
121 importantTotalUnpacked += unpackSize;
|
rlm@1
|
122 extractFolderInfoVector.Back().UnpackSize = unpackSize;
|
rlm@1
|
123 }
|
rlm@1
|
124
|
rlm@1
|
125 CExtractFolderInfo &efi = extractFolderInfoVector.Back();
|
rlm@1
|
126
|
rlm@1
|
127 // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex];
|
rlm@1
|
128 CNum startIndex = db.FolderStartFileIndex[folderIndex];
|
rlm@1
|
129 for (CNum index = efi.ExtractStatuses.Size();
|
rlm@1
|
130 index <= fileIndex - startIndex; index++)
|
rlm@1
|
131 {
|
rlm@1
|
132 // UInt64 unpackSize = _db.Files[startIndex + index].UnpackSize;
|
rlm@1
|
133 // Count partial_folder_size
|
rlm@1
|
134 // efi.UnpackSize += unpackSize;
|
rlm@1
|
135 // importantTotalUnpacked += unpackSize;
|
rlm@1
|
136 efi.ExtractStatuses.Add(index == fileIndex - startIndex);
|
rlm@1
|
137 }
|
rlm@1
|
138 }
|
rlm@1
|
139 }
|
rlm@1
|
140
|
rlm@1
|
141 extractCallback->SetTotal(importantTotalUnpacked);
|
rlm@1
|
142
|
rlm@1
|
143 CDecoder decoder(
|
rlm@1
|
144 #ifdef _ST_MODE
|
rlm@1
|
145 false
|
rlm@1
|
146 #else
|
rlm@1
|
147 true
|
rlm@1
|
148 #endif
|
rlm@1
|
149 );
|
rlm@1
|
150 // CDecoder1 decoder;
|
rlm@1
|
151
|
rlm@1
|
152 UInt64 currentTotalPacked = 0;
|
rlm@1
|
153 UInt64 currentTotalUnpacked = 0;
|
rlm@1
|
154 UInt64 totalFolderUnpacked;
|
rlm@1
|
155 UInt64 totalFolderPacked;
|
rlm@1
|
156
|
rlm@1
|
157 CLocalProgress *lps = new CLocalProgress;
|
rlm@1
|
158 CMyComPtr<ICompressProgressInfo> progress = lps;
|
rlm@1
|
159 lps->Init(extractCallback, false);
|
rlm@1
|
160
|
rlm@1
|
161 for(int i = 0; i < extractFolderInfoVector.Size(); i++,
|
rlm@1
|
162 currentTotalUnpacked += totalFolderUnpacked,
|
rlm@1
|
163 currentTotalPacked += totalFolderPacked)
|
rlm@1
|
164 {
|
rlm@1
|
165 lps->OutSize = currentTotalUnpacked;
|
rlm@1
|
166 lps->InSize = currentTotalPacked;
|
rlm@1
|
167 RINOK(lps->SetCur());
|
rlm@1
|
168
|
rlm@1
|
169 const CExtractFolderInfo &efi = extractFolderInfoVector[i];
|
rlm@1
|
170 totalFolderUnpacked = efi.UnpackSize;
|
rlm@1
|
171
|
rlm@1
|
172 totalFolderPacked = 0;
|
rlm@1
|
173
|
rlm@1
|
174 CFolderOutStream *folderOutStream = new CFolderOutStream;
|
rlm@1
|
175 CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
|
rlm@1
|
176
|
rlm@1
|
177 #ifdef _7Z_VOL
|
rlm@1
|
178 const CVolume &volume = _volumes[efi.VolumeIndex];
|
rlm@1
|
179 const CArchiveDatabaseEx &db = volume.Database;
|
rlm@1
|
180 #else
|
rlm@1
|
181 const CArchiveDatabaseEx &db = _db;
|
rlm@1
|
182 #endif
|
rlm@1
|
183
|
rlm@1
|
184 CNum startIndex;
|
rlm@1
|
185 if (efi.FileIndex != kNumNoIndex)
|
rlm@1
|
186 startIndex = efi.FileIndex;
|
rlm@1
|
187 else
|
rlm@1
|
188 startIndex = db.FolderStartFileIndex[efi.FolderIndex];
|
rlm@1
|
189
|
rlm@1
|
190
|
rlm@1
|
191 HRESULT result = folderOutStream->Init(&db,
|
rlm@1
|
192 #ifdef _7Z_VOL
|
rlm@1
|
193 volume.StartRef2Index,
|
rlm@1
|
194 #else
|
rlm@1
|
195 0,
|
rlm@1
|
196 #endif
|
rlm@1
|
197 startIndex,
|
rlm@1
|
198 &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0);
|
rlm@1
|
199
|
rlm@1
|
200 RINOK(result);
|
rlm@1
|
201
|
rlm@1
|
202 if (efi.FileIndex != kNumNoIndex)
|
rlm@1
|
203 continue;
|
rlm@1
|
204
|
rlm@1
|
205 CNum folderIndex = efi.FolderIndex;
|
rlm@1
|
206 const CFolder &folderInfo = db.Folders[folderIndex];
|
rlm@1
|
207
|
rlm@1
|
208 totalFolderPacked = _db.GetFolderFullPackSize(folderIndex);
|
rlm@1
|
209
|
rlm@1
|
210 CNum packStreamIndex = db.FolderStartPackStreamIndex[folderIndex];
|
rlm@1
|
211 UInt64 folderStartPackPos = db.GetFolderStreamPos(folderIndex, 0);
|
rlm@1
|
212
|
rlm@1
|
213 #ifndef _NO_CRYPTO
|
rlm@1
|
214 CMyComPtr<ICryptoGetTextPassword> getTextPassword;
|
rlm@1
|
215 if (extractCallback)
|
rlm@1
|
216 extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
|
rlm@1
|
217 #endif
|
rlm@1
|
218
|
rlm@1
|
219 try
|
rlm@1
|
220 {
|
rlm@1
|
221 #ifndef _NO_CRYPTO
|
rlm@1
|
222 bool passwordIsDefined;
|
rlm@1
|
223 #endif
|
rlm@1
|
224
|
rlm@1
|
225 HRESULT result = decoder.Decode(
|
rlm@1
|
226 EXTERNAL_CODECS_VARS
|
rlm@1
|
227 #ifdef _7Z_VOL
|
rlm@1
|
228 volume.Stream,
|
rlm@1
|
229 #else
|
rlm@1
|
230 _inStream,
|
rlm@1
|
231 #endif
|
rlm@1
|
232 folderStartPackPos,
|
rlm@1
|
233 &db.PackSizes[packStreamIndex],
|
rlm@1
|
234 folderInfo,
|
rlm@1
|
235 outStream,
|
rlm@1
|
236 progress
|
rlm@1
|
237 #ifndef _NO_CRYPTO
|
rlm@1
|
238 , getTextPassword, passwordIsDefined
|
rlm@1
|
239 #endif
|
rlm@1
|
240 #ifdef COMPRESS_MT
|
rlm@1
|
241 , true, _numThreads
|
rlm@1
|
242 #endif
|
rlm@1
|
243 );
|
rlm@1
|
244
|
rlm@1
|
245 if (result == S_FALSE)
|
rlm@1
|
246 {
|
rlm@1
|
247 RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
|
rlm@1
|
248 continue;
|
rlm@1
|
249 }
|
rlm@1
|
250 if (result == E_NOTIMPL)
|
rlm@1
|
251 {
|
rlm@1
|
252 RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
|
rlm@1
|
253 continue;
|
rlm@1
|
254 }
|
rlm@1
|
255 if (result != S_OK)
|
rlm@1
|
256 return result;
|
rlm@1
|
257 if (folderOutStream->WasWritingFinished() != S_OK)
|
rlm@1
|
258 {
|
rlm@1
|
259 RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
|
rlm@1
|
260 continue;
|
rlm@1
|
261 }
|
rlm@1
|
262 }
|
rlm@1
|
263 catch(...)
|
rlm@1
|
264 {
|
rlm@1
|
265 RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
|
rlm@1
|
266 continue;
|
rlm@1
|
267 }
|
rlm@1
|
268 }
|
rlm@1
|
269 return S_OK;
|
rlm@1
|
270 COM_TRY_END
|
rlm@1
|
271 }
|
rlm@1
|
272
|
rlm@1
|
273 }}
|