|
1 // 7zDecode.cpp |
|
2 |
|
3 #include "StdAfx.h" |
|
4 |
|
5 #include "7zDecode.h" |
|
6 |
|
7 #include "../../IPassword.h" |
|
8 #include "../../Common/LockedStream.h" |
|
9 #include "../../Common/StreamObjects.h" |
|
10 #include "../../Common/ProgressUtils.h" |
|
11 #include "../../Common/LimitedStreams.h" |
|
12 #include "../Common/FilterCoder.h" |
|
13 |
|
14 #include "7zMethods.h" |
|
15 |
|
16 #ifdef COMPRESS_LZMA |
|
17 #include "../../Compress/LZMA/LZMADecoder.h" |
|
18 static NArchive::N7z::CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 }; |
|
19 #endif |
|
20 |
|
21 #ifdef COMPRESS_PPMD |
|
22 #include "../../Compress/PPMD/PPMDDecoder.h" |
|
23 static NArchive::N7z::CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 }; |
|
24 #endif |
|
25 |
|
26 #ifdef COMPRESS_BCJ_X86 |
|
27 #include "../../Compress/Branch/x86.h" |
|
28 static NArchive::N7z::CMethodID k_BCJ_X86 = { { 0x3, 0x3, 0x1, 0x3 }, 4 }; |
|
29 #endif |
|
30 |
|
31 #ifdef COMPRESS_BCJ2 |
|
32 #include "../../Compress/Branch/x86_2.h" |
|
33 static NArchive::N7z::CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 }; |
|
34 #endif |
|
35 |
|
36 #ifdef COMPRESS_DEFLATE |
|
37 #ifndef COMPRESS_DEFLATE_DECODER |
|
38 #define COMPRESS_DEFLATE_DECODER |
|
39 #endif |
|
40 #endif |
|
41 |
|
42 #ifdef COMPRESS_DEFLATE_DECODER |
|
43 #include "../../Compress/Deflate/DeflateDecoder.h" |
|
44 static NArchive::N7z::CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 }; |
|
45 #endif |
|
46 |
|
47 #ifdef COMPRESS_BZIP2 |
|
48 #ifndef COMPRESS_BZIP2_DECODER |
|
49 #define COMPRESS_BZIP2_DECODER |
|
50 #endif |
|
51 #endif |
|
52 |
|
53 #ifdef COMPRESS_BZIP2_DECODER |
|
54 #include "../../Compress/BZip2/BZip2Decoder.h" |
|
55 static NArchive::N7z::CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 }; |
|
56 #endif |
|
57 |
|
58 #ifdef COMPRESS_COPY |
|
59 #include "../../Compress/Copy/CopyCoder.h" |
|
60 static NArchive::N7z::CMethodID k_Copy = { { 0x0 }, 1 }; |
|
61 #endif |
|
62 |
|
63 #ifdef CRYPTO_7ZAES |
|
64 #include "../../Crypto/7zAES/7zAES.h" |
|
65 static NArchive::N7z::CMethodID k_7zAES = { { 0x6, 0xF1, 0x07, 0x01 }, 4 }; |
|
66 #endif |
|
67 |
|
68 namespace NArchive { |
|
69 namespace N7z { |
|
70 |
|
71 static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, |
|
72 CBindInfoEx &bindInfo) |
|
73 { |
|
74 bindInfo.Clear(); |
|
75 int i; |
|
76 for (i = 0; i < folder.BindPairs.Size(); i++) |
|
77 { |
|
78 NCoderMixer2::CBindPair bindPair; |
|
79 bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; |
|
80 bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; |
|
81 bindInfo.BindPairs.Add(bindPair); |
|
82 } |
|
83 UInt32 outStreamIndex = 0; |
|
84 for (i = 0; i < folder.Coders.Size(); i++) |
|
85 { |
|
86 NCoderMixer2::CCoderStreamsInfo coderStreamsInfo; |
|
87 const CCoderInfo &coderInfo = folder.Coders[i]; |
|
88 coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; |
|
89 coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; |
|
90 bindInfo.Coders.Add(coderStreamsInfo); |
|
91 const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front(); |
|
92 bindInfo.CoderMethodIDs.Add(altCoderInfo.MethodID); |
|
93 for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) |
|
94 if (folder.FindBindPairForOutStream(outStreamIndex) < 0) |
|
95 bindInfo.OutStreams.Add(outStreamIndex); |
|
96 } |
|
97 for (i = 0; i < folder.PackStreams.Size(); i++) |
|
98 bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]); |
|
99 } |
|
100 |
|
101 static bool AreCodersEqual(const NCoderMixer2::CCoderStreamsInfo &a1, |
|
102 const NCoderMixer2::CCoderStreamsInfo &a2) |
|
103 { |
|
104 return (a1.NumInStreams == a2.NumInStreams) && |
|
105 (a1.NumOutStreams == a2.NumOutStreams); |
|
106 } |
|
107 |
|
108 static bool AreBindPairsEqual(const NCoderMixer2::CBindPair &a1, const NCoderMixer2::CBindPair &a2) |
|
109 { |
|
110 return (a1.InIndex == a2.InIndex) && |
|
111 (a1.OutIndex == a2.OutIndex); |
|
112 } |
|
113 |
|
114 static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) |
|
115 { |
|
116 if (a1.Coders.Size() != a2.Coders.Size()) |
|
117 return false; |
|
118 int i; |
|
119 for (i = 0; i < a1.Coders.Size(); i++) |
|
120 if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) |
|
121 return false; |
|
122 if (a1.BindPairs.Size() != a2.BindPairs.Size()) |
|
123 return false; |
|
124 for (i = 0; i < a1.BindPairs.Size(); i++) |
|
125 if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i])) |
|
126 return false; |
|
127 for (i = 0; i < a1.CoderMethodIDs.Size(); i++) |
|
128 if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) |
|
129 return false; |
|
130 if (a1.InStreams.Size() != a2.InStreams.Size()) |
|
131 return false; |
|
132 if (a1.OutStreams.Size() != a2.OutStreams.Size()) |
|
133 return false; |
|
134 return true; |
|
135 } |
|
136 |
|
137 CDecoder::CDecoder(bool multiThread) |
|
138 { |
|
139 #ifndef _ST_MODE |
|
140 multiThread = true; |
|
141 #endif |
|
142 _multiThread = multiThread; |
|
143 _bindInfoExPrevIsDefinded = false; |
|
144 #ifndef EXCLUDE_COM |
|
145 LoadMethodMap(); |
|
146 #endif |
|
147 } |
|
148 |
|
149 HRESULT CDecoder::Decode(IInStream *inStream, |
|
150 UInt64 startPos, |
|
151 const UInt64 *packSizes, |
|
152 const CFolder &folderInfo, |
|
153 ISequentialOutStream *outStream, |
|
154 ICompressProgressInfo *compressProgress |
|
155 #ifndef _NO_CRYPTO |
|
156 , ICryptoGetTextPassword *getTextPassword |
|
157 #endif |
|
158 #ifdef COMPRESS_MT |
|
159 , bool mtMode, UInt32 numThreads |
|
160 #endif |
|
161 ) |
|
162 { |
|
163 CObjectVector< CMyComPtr<ISequentialInStream> > inStreams; |
|
164 |
|
165 CLockedInStream lockedInStream; |
|
166 lockedInStream.Init(inStream); |
|
167 |
|
168 for (int j = 0; j < folderInfo.PackStreams.Size(); j++) |
|
169 { |
|
170 CLockedSequentialInStreamImp *lockedStreamImpSpec = new |
|
171 CLockedSequentialInStreamImp; |
|
172 CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec; |
|
173 lockedStreamImpSpec->Init(&lockedInStream, startPos); |
|
174 startPos += packSizes[j]; |
|
175 |
|
176 CLimitedSequentialInStream *streamSpec = new |
|
177 CLimitedSequentialInStream; |
|
178 CMyComPtr<ISequentialInStream> inStream = streamSpec; |
|
179 streamSpec->Init(lockedStreamImp, packSizes[j]); |
|
180 inStreams.Add(inStream); |
|
181 } |
|
182 |
|
183 int numCoders = folderInfo.Coders.Size(); |
|
184 |
|
185 CBindInfoEx bindInfo; |
|
186 ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); |
|
187 bool createNewCoders; |
|
188 if (!_bindInfoExPrevIsDefinded) |
|
189 createNewCoders = true; |
|
190 else |
|
191 createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); |
|
192 if (createNewCoders) |
|
193 { |
|
194 int i; |
|
195 _decoders.Clear(); |
|
196 // _decoders2.Clear(); |
|
197 |
|
198 _mixerCoder.Release(); |
|
199 |
|
200 if (_multiThread) |
|
201 { |
|
202 _mixerCoderMTSpec = new NCoderMixer2::CCoderMixer2MT; |
|
203 _mixerCoder = _mixerCoderMTSpec; |
|
204 _mixerCoderCommon = _mixerCoderMTSpec; |
|
205 } |
|
206 else |
|
207 { |
|
208 #ifdef _ST_MODE |
|
209 _mixerCoderSTSpec = new NCoderMixer2::CCoderMixer2ST; |
|
210 _mixerCoder = _mixerCoderSTSpec; |
|
211 _mixerCoderCommon = _mixerCoderSTSpec; |
|
212 #endif |
|
213 } |
|
214 _mixerCoderCommon->SetBindInfo(bindInfo); |
|
215 |
|
216 for (i = 0; i < numCoders; i++) |
|
217 { |
|
218 const CCoderInfo &coderInfo = folderInfo.Coders[i]; |
|
219 const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front(); |
|
220 #ifndef EXCLUDE_COM |
|
221 CMethodInfo methodInfo; |
|
222 if (!GetMethodInfo(altCoderInfo.MethodID, methodInfo)) |
|
223 return E_NOTIMPL; |
|
224 #endif |
|
225 |
|
226 if (coderInfo.IsSimpleCoder()) |
|
227 { |
|
228 CMyComPtr<ICompressCoder> decoder; |
|
229 CMyComPtr<ICompressFilter> filter; |
|
230 |
|
231 #ifdef COMPRESS_LZMA |
|
232 if (altCoderInfo.MethodID == k_LZMA) |
|
233 decoder = new NCompress::NLZMA::CDecoder; |
|
234 #endif |
|
235 |
|
236 #ifdef COMPRESS_PPMD |
|
237 if (altCoderInfo.MethodID == k_PPMD) |
|
238 decoder = new NCompress::NPPMD::CDecoder; |
|
239 #endif |
|
240 |
|
241 #ifdef COMPRESS_BCJ_X86 |
|
242 if (altCoderInfo.MethodID == k_BCJ_X86) |
|
243 filter = new CBCJ_x86_Decoder; |
|
244 #endif |
|
245 |
|
246 #ifdef COMPRESS_DEFLATE_DECODER |
|
247 if (altCoderInfo.MethodID == k_Deflate) |
|
248 decoder = new NCompress::NDeflate::NDecoder::CCOMCoder; |
|
249 #endif |
|
250 |
|
251 #ifdef COMPRESS_BZIP2_DECODER |
|
252 if (altCoderInfo.MethodID == k_BZip2) |
|
253 decoder = new NCompress::NBZip2::CDecoder; |
|
254 #endif |
|
255 |
|
256 #ifdef COMPRESS_COPY |
|
257 if (altCoderInfo.MethodID == k_Copy) |
|
258 decoder = new NCompress::CCopyCoder; |
|
259 #endif |
|
260 |
|
261 #ifdef CRYPTO_7ZAES |
|
262 if (altCoderInfo.MethodID == k_7zAES) |
|
263 filter = new NCrypto::NSevenZ::CDecoder; |
|
264 #endif |
|
265 |
|
266 if (filter) |
|
267 { |
|
268 CFilterCoder *coderSpec = new CFilterCoder; |
|
269 decoder = coderSpec; |
|
270 coderSpec->Filter = filter; |
|
271 } |
|
272 #ifndef EXCLUDE_COM |
|
273 if (decoder == 0) |
|
274 { |
|
275 RINOK(_libraries.CreateCoderSpec(methodInfo.FilePath, |
|
276 methodInfo.Decoder, &decoder)); |
|
277 } |
|
278 #endif |
|
279 |
|
280 if (decoder == 0) |
|
281 return E_NOTIMPL; |
|
282 |
|
283 _decoders.Add((IUnknown *)decoder); |
|
284 |
|
285 if (_multiThread) |
|
286 _mixerCoderMTSpec->AddCoder(decoder); |
|
287 #ifdef _ST_MODE |
|
288 else |
|
289 _mixerCoderSTSpec->AddCoder(decoder, false); |
|
290 #endif |
|
291 } |
|
292 else |
|
293 { |
|
294 CMyComPtr<ICompressCoder2> decoder; |
|
295 |
|
296 #ifdef COMPRESS_BCJ2 |
|
297 if (altCoderInfo.MethodID == k_BCJ2) |
|
298 decoder = new CBCJ2_x86_Decoder; |
|
299 #endif |
|
300 |
|
301 #ifndef EXCLUDE_COM |
|
302 if (decoder == 0) |
|
303 { |
|
304 RINOK(_libraries.CreateCoder2(methodInfo.FilePath, |
|
305 methodInfo.Decoder, &decoder)); |
|
306 } |
|
307 #endif |
|
308 |
|
309 if (decoder == 0) |
|
310 return E_NOTIMPL; |
|
311 |
|
312 _decoders.Add((IUnknown *)decoder); |
|
313 if (_multiThread) |
|
314 _mixerCoderMTSpec->AddCoder2(decoder); |
|
315 #ifdef _ST_MODE |
|
316 else |
|
317 _mixerCoderSTSpec->AddCoder2(decoder, false); |
|
318 #endif |
|
319 } |
|
320 } |
|
321 _bindInfoExPrev = bindInfo; |
|
322 _bindInfoExPrevIsDefinded = true; |
|
323 } |
|
324 int i; |
|
325 _mixerCoderCommon->ReInit(); |
|
326 |
|
327 UInt32 packStreamIndex = 0, unPackStreamIndex = 0; |
|
328 UInt32 coderIndex = 0; |
|
329 // UInt32 coder2Index = 0; |
|
330 |
|
331 for (i = 0; i < numCoders; i++) |
|
332 { |
|
333 const CCoderInfo &coderInfo = folderInfo.Coders[i]; |
|
334 const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front(); |
|
335 CMyComPtr<IUnknown> &decoder = _decoders[coderIndex]; |
|
336 |
|
337 { |
|
338 CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; |
|
339 HRESULT result = decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); |
|
340 if (setDecoderProperties) |
|
341 { |
|
342 const CByteBuffer &properties = altCoderInfo.Properties; |
|
343 size_t size = properties.GetCapacity(); |
|
344 if (size > 0xFFFFFFFF) |
|
345 return E_NOTIMPL; |
|
346 if (size > 0) |
|
347 { |
|
348 RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, (UInt32)size)); |
|
349 } |
|
350 } |
|
351 } |
|
352 |
|
353 #ifdef COMPRESS_MT |
|
354 if (mtMode) |
|
355 { |
|
356 CMyComPtr<ICompressSetCoderMt> setCoderMt; |
|
357 decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); |
|
358 if (setCoderMt) |
|
359 { |
|
360 RINOK(setCoderMt->SetNumberOfThreads(numThreads)); |
|
361 } |
|
362 } |
|
363 #endif |
|
364 |
|
365 #ifndef _NO_CRYPTO |
|
366 { |
|
367 CMyComPtr<ICryptoSetPassword> cryptoSetPassword; |
|
368 HRESULT result = decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); |
|
369 if (cryptoSetPassword) |
|
370 { |
|
371 if (getTextPassword == 0) |
|
372 return E_FAIL; |
|
373 CMyComBSTR password; |
|
374 RINOK(getTextPassword->CryptoGetTextPassword(&password)); |
|
375 CByteBuffer buffer; |
|
376 UString unicodePassword(password); |
|
377 const UInt32 sizeInBytes = unicodePassword.Length() * 2; |
|
378 buffer.SetCapacity(sizeInBytes); |
|
379 for (int i = 0; i < unicodePassword.Length(); i++) |
|
380 { |
|
381 wchar_t c = unicodePassword[i]; |
|
382 ((Byte *)buffer)[i * 2] = (Byte)c; |
|
383 ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); |
|
384 } |
|
385 RINOK(cryptoSetPassword->CryptoSetPassword( |
|
386 (const Byte *)buffer, sizeInBytes)); |
|
387 } |
|
388 } |
|
389 #endif |
|
390 |
|
391 coderIndex++; |
|
392 |
|
393 UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; |
|
394 UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; |
|
395 CRecordVector<const UInt64 *> packSizesPointers; |
|
396 CRecordVector<const UInt64 *> unPackSizesPointers; |
|
397 packSizesPointers.Reserve(numInStreams); |
|
398 unPackSizesPointers.Reserve(numOutStreams); |
|
399 UInt32 j; |
|
400 for (j = 0; j < numOutStreams; j++, unPackStreamIndex++) |
|
401 unPackSizesPointers.Add(&folderInfo.UnPackSizes[unPackStreamIndex]); |
|
402 |
|
403 for (j = 0; j < numInStreams; j++, packStreamIndex++) |
|
404 { |
|
405 int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); |
|
406 if (bindPairIndex >= 0) |
|
407 packSizesPointers.Add( |
|
408 &folderInfo.UnPackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]); |
|
409 else |
|
410 { |
|
411 int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); |
|
412 if (index < 0) |
|
413 return E_FAIL; |
|
414 packSizesPointers.Add(&packSizes[index]); |
|
415 } |
|
416 } |
|
417 |
|
418 _mixerCoderCommon->SetCoderInfo(i, |
|
419 &packSizesPointers.Front(), |
|
420 &unPackSizesPointers.Front()); |
|
421 } |
|
422 UInt32 mainCoder, temp; |
|
423 bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); |
|
424 |
|
425 if (_multiThread) |
|
426 _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); |
|
427 /* |
|
428 else |
|
429 _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; |
|
430 */ |
|
431 |
|
432 if (numCoders == 0) |
|
433 return 0; |
|
434 CRecordVector<ISequentialInStream *> inStreamPointers; |
|
435 inStreamPointers.Reserve(inStreams.Size()); |
|
436 for (i = 0; i < inStreams.Size(); i++) |
|
437 inStreamPointers.Add(inStreams[i]); |
|
438 ISequentialOutStream *outStreamPointer = outStream; |
|
439 return _mixerCoder->Code(&inStreamPointers.Front(), NULL, |
|
440 inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress); |
|
441 } |
|
442 |
|
443 }} |