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