Mercurial > vba-linux
comparison src/win32/7zip/7z/CPP/7zip/Archive/Zip/ZipHandler.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 // ZipHandler.cpp | |
2 | |
3 #include "StdAfx.h" | |
4 | |
5 #include "Common/ComTry.h" | |
6 #include "Common/Defs.h" | |
7 #include "Common/IntToString.h" | |
8 #include "Common/StringConvert.h" | |
9 | |
10 #include "Windows/PropVariant.h" | |
11 #include "Windows/Time.h" | |
12 | |
13 #include "../../IPassword.h" | |
14 | |
15 #include "../../Common/CreateCoder.h" | |
16 #include "../../Common/FilterCoder.h" | |
17 #include "../../Common/ProgressUtils.h" | |
18 #include "../../Common/StreamObjects.h" | |
19 #include "../../Common/StreamUtils.h" | |
20 | |
21 #include "../../Compress/CopyCoder.h" | |
22 #include "../../Compress/LzmaDecoder.h" | |
23 #include "../../Compress/ImplodeDecoder.h" | |
24 #include "../../Compress/ShrinkDecoder.h" | |
25 | |
26 #include "../../Crypto/WzAes.h" | |
27 #include "../../Crypto/ZipCrypto.h" | |
28 #include "../../Crypto/ZipStrong.h" | |
29 | |
30 #include "../Common/ItemNameUtils.h" | |
31 #include "../Common/OutStreamWithCRC.h" | |
32 | |
33 #include "ZipHandler.h" | |
34 | |
35 using namespace NWindows; | |
36 | |
37 namespace NArchive { | |
38 namespace NZip { | |
39 | |
40 // static const CMethodId kMethodId_Store = 0; | |
41 static const CMethodId kMethodId_ZipBase = 0x040100; | |
42 static const CMethodId kMethodId_BZip2 = 0x040202; | |
43 | |
44 const wchar_t *kHostOS[] = | |
45 { | |
46 L"FAT", | |
47 L"AMIGA", | |
48 L"VMS", | |
49 L"Unix", | |
50 L"VM/CMS", | |
51 L"Atari", | |
52 L"HPFS", | |
53 L"Macintosh", | |
54 L"Z-System", | |
55 L"CP/M", | |
56 L"TOPS-20", | |
57 L"NTFS", | |
58 L"SMS/QDOS", | |
59 L"Acorn", | |
60 L"VFAT", | |
61 L"MVS", | |
62 L"BeOS", | |
63 L"Tandem", | |
64 L"OS/400", | |
65 L"OS/X" | |
66 }; | |
67 | |
68 | |
69 static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]); | |
70 | |
71 static const wchar_t *kUnknownOS = L"Unknown"; | |
72 | |
73 STATPROPSTG kProps[] = | |
74 { | |
75 { NULL, kpidPath, VT_BSTR}, | |
76 { NULL, kpidIsDir, VT_BOOL}, | |
77 { NULL, kpidSize, VT_UI8}, | |
78 { NULL, kpidPackSize, VT_UI8}, | |
79 { NULL, kpidMTime, VT_FILETIME}, | |
80 { NULL, kpidCTime, VT_FILETIME}, | |
81 { NULL, kpidATime, VT_FILETIME}, | |
82 | |
83 { NULL, kpidAttrib, VT_UI4}, | |
84 | |
85 { NULL, kpidEncrypted, VT_BOOL}, | |
86 { NULL, kpidComment, VT_BSTR}, | |
87 | |
88 { NULL, kpidCRC, VT_UI4}, | |
89 | |
90 { NULL, kpidMethod, VT_BSTR}, | |
91 { NULL, kpidHostOS, VT_BSTR} | |
92 | |
93 // { NULL, kpidUnpackVer, VT_UI1}, | |
94 }; | |
95 | |
96 const wchar_t *kMethods[] = | |
97 { | |
98 L"Store", | |
99 L"Shrink", | |
100 L"Reduced1", | |
101 L"Reduced2", | |
102 L"Reduced2", | |
103 L"Reduced3", | |
104 L"Implode", | |
105 L"Tokenizing", | |
106 L"Deflate", | |
107 L"Deflate64", | |
108 L"PKImploding" | |
109 }; | |
110 | |
111 const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]); | |
112 const wchar_t *kBZip2Method = L"BZip2"; | |
113 const wchar_t *kLZMAMethod = L"LZMA"; | |
114 const wchar_t *kJpegMethod = L"Jpeg"; | |
115 const wchar_t *kWavPackMethod = L"WavPack"; | |
116 const wchar_t *kPPMdMethod = L"PPMd"; | |
117 const wchar_t *kAESMethod = L"AES"; | |
118 const wchar_t *kZipCryptoMethod = L"ZipCrypto"; | |
119 const wchar_t *kStrongCryptoMethod = L"StrongCrypto"; | |
120 | |
121 struct CStrongCryptoPair | |
122 { | |
123 UInt16 Id; | |
124 const wchar_t *Name; | |
125 }; | |
126 | |
127 CStrongCryptoPair g_StrongCryptoPairs[] = | |
128 { | |
129 { NStrongCryptoFlags::kDES, L"DES" }, | |
130 { NStrongCryptoFlags::kRC2old, L"RC2a" }, | |
131 { NStrongCryptoFlags::k3DES168, L"3DES-168" }, | |
132 { NStrongCryptoFlags::k3DES112, L"3DES-112" }, | |
133 { NStrongCryptoFlags::kAES128, L"pkAES-128" }, | |
134 { NStrongCryptoFlags::kAES192, L"pkAES-192" }, | |
135 { NStrongCryptoFlags::kAES256, L"pkAES-256" }, | |
136 { NStrongCryptoFlags::kRC2, L"RC2" }, | |
137 { NStrongCryptoFlags::kBlowfish, L"Blowfish" }, | |
138 { NStrongCryptoFlags::kTwofish, L"Twofish" }, | |
139 { NStrongCryptoFlags::kRC4, L"RC4" } | |
140 }; | |
141 | |
142 STATPROPSTG kArcProps[] = | |
143 { | |
144 { NULL, kpidBit64, VT_BOOL}, | |
145 { NULL, kpidComment, VT_BSTR} | |
146 }; | |
147 | |
148 CHandler::CHandler() | |
149 { | |
150 InitMethodProperties(); | |
151 } | |
152 | |
153 static AString BytesToString(const CByteBuffer &data) | |
154 { | |
155 AString s; | |
156 int size = (int)data.GetCapacity(); | |
157 if (size > 0) | |
158 { | |
159 char *p = s.GetBuffer(size + 1); | |
160 memcpy(p, (const Byte *)data, size); | |
161 p[size] = '\0'; | |
162 s.ReleaseBuffer(); | |
163 } | |
164 return s; | |
165 } | |
166 | |
167 IMP_IInArchive_Props | |
168 IMP_IInArchive_ArcProps | |
169 | |
170 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) | |
171 { | |
172 COM_TRY_BEGIN | |
173 NWindows::NCOM::CPropVariant prop; | |
174 switch(propID) | |
175 { | |
176 case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break; | |
177 case kpidComment: | |
178 prop = MultiByteToUnicodeString(BytesToString(m_Archive.m_ArchiveInfo.Comment), CP_ACP); | |
179 break; | |
180 } | |
181 prop.Detach(value); | |
182 COM_TRY_END | |
183 return S_OK; | |
184 } | |
185 | |
186 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) | |
187 { | |
188 *numItems = m_Items.Size(); | |
189 return S_OK; | |
190 } | |
191 | |
192 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) | |
193 { | |
194 COM_TRY_BEGIN | |
195 NWindows::NCOM::CPropVariant prop; | |
196 const CItemEx &item = m_Items[index]; | |
197 switch(propID) | |
198 { | |
199 case kpidPath: prop = NItemName::GetOSName2(item.GetUnicodeString(item.Name)); break; | |
200 case kpidIsDir: prop = item.IsDir(); break; | |
201 case kpidSize: prop = item.UnPackSize; break; | |
202 case kpidPackSize: prop = item.PackSize; break; | |
203 case kpidTimeType: | |
204 { | |
205 FILETIME utcFileTime; | |
206 if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kTagTime, utcFileTime)) | |
207 prop = (UInt32)NFileTimeType::kWindows; | |
208 break; | |
209 } | |
210 case kpidCTime: | |
211 { | |
212 FILETIME ft; | |
213 if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft)) | |
214 prop = ft; | |
215 break; | |
216 } | |
217 case kpidATime: | |
218 { | |
219 FILETIME ft; | |
220 if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft)) | |
221 prop = ft; | |
222 break; | |
223 } | |
224 case kpidMTime: | |
225 { | |
226 FILETIME utcFileTime; | |
227 if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utcFileTime)) | |
228 { | |
229 FILETIME localFileTime; | |
230 if (NTime::DosTimeToFileTime(item.Time, localFileTime)) | |
231 { | |
232 if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) | |
233 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; | |
234 } | |
235 else | |
236 utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; | |
237 } | |
238 prop = utcFileTime; | |
239 break; | |
240 } | |
241 case kpidAttrib: prop = item.GetWinAttributes(); break; | |
242 case kpidEncrypted: prop = item.IsEncrypted(); break; | |
243 case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break; | |
244 case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break; | |
245 case kpidMethod: | |
246 { | |
247 UInt16 methodId = item.CompressionMethod; | |
248 UString method; | |
249 if (item.IsEncrypted()) | |
250 { | |
251 if (methodId == NFileHeader::NCompressionMethod::kWzAES) | |
252 { | |
253 method = kAESMethod; | |
254 CWzAesExtraField aesField; | |
255 if (item.CentralExtra.GetWzAesField(aesField)) | |
256 { | |
257 method += L"-"; | |
258 wchar_t s[32]; | |
259 ConvertUInt64ToString((aesField.Strength + 1) * 64 , s); | |
260 method += s; | |
261 method += L" "; | |
262 methodId = aesField.Method; | |
263 } | |
264 } | |
265 else | |
266 { | |
267 if (item.IsStrongEncrypted()) | |
268 { | |
269 CStrongCryptoField f; | |
270 bool finded = false; | |
271 if (item.CentralExtra.GetStrongCryptoField(f)) | |
272 { | |
273 for (int i = 0; i < sizeof(g_StrongCryptoPairs) / sizeof(g_StrongCryptoPairs[0]); i++) | |
274 { | |
275 const CStrongCryptoPair &pair = g_StrongCryptoPairs[i]; | |
276 if (f.AlgId == pair.Id) | |
277 { | |
278 method += pair.Name; | |
279 finded = true; | |
280 break; | |
281 } | |
282 } | |
283 } | |
284 if (!finded) | |
285 method += kStrongCryptoMethod; | |
286 } | |
287 else | |
288 method += kZipCryptoMethod; | |
289 method += L" "; | |
290 } | |
291 } | |
292 if (methodId < kNumMethods) | |
293 method += kMethods[methodId]; | |
294 else switch (methodId) | |
295 { | |
296 case NFileHeader::NCompressionMethod::kLZMA: | |
297 method += kLZMAMethod; | |
298 if (item.IsLzmaEOS()) | |
299 method += L":EOS"; | |
300 break; | |
301 case NFileHeader::NCompressionMethod::kBZip2: method += kBZip2Method; break; | |
302 case NFileHeader::NCompressionMethod::kJpeg: method += kJpegMethod; break; | |
303 case NFileHeader::NCompressionMethod::kWavPack: method += kWavPackMethod; break; | |
304 case NFileHeader::NCompressionMethod::kPPMd: method += kPPMdMethod; break; | |
305 default: | |
306 { | |
307 wchar_t s[32]; | |
308 ConvertUInt64ToString(methodId, s); | |
309 method += s; | |
310 } | |
311 } | |
312 prop = method; | |
313 break; | |
314 } | |
315 case kpidHostOS: | |
316 prop = (item.MadeByVersion.HostOS < kNumHostOSes) ? | |
317 (kHostOS[item.MadeByVersion.HostOS]) : kUnknownOS; | |
318 break; | |
319 } | |
320 prop.Detach(value); | |
321 return S_OK; | |
322 COM_TRY_END | |
323 } | |
324 | |
325 class CProgressImp: public CProgressVirt | |
326 { | |
327 CMyComPtr<IArchiveOpenCallback> _callback; | |
328 public: | |
329 STDMETHOD(SetTotal)(UInt64 numFiles); | |
330 STDMETHOD(SetCompleted)(UInt64 numFiles); | |
331 CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {} | |
332 }; | |
333 | |
334 STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles) | |
335 { | |
336 if (_callback) | |
337 return _callback->SetTotal(&numFiles, NULL); | |
338 return S_OK; | |
339 } | |
340 | |
341 STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles) | |
342 { | |
343 if (_callback) | |
344 return _callback->SetCompleted(&numFiles, NULL); | |
345 return S_OK; | |
346 } | |
347 | |
348 STDMETHODIMP CHandler::Open(IInStream *inStream, | |
349 const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) | |
350 { | |
351 COM_TRY_BEGIN | |
352 try | |
353 { | |
354 Close(); | |
355 RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); | |
356 RINOK(m_Archive.Open(inStream, maxCheckStartPosition)); | |
357 CProgressImp progressImp(callback); | |
358 return m_Archive.ReadHeaders(m_Items, &progressImp); | |
359 } | |
360 catch(const CInArchiveException &) { Close(); return S_FALSE; } | |
361 catch(...) { Close(); throw; } | |
362 COM_TRY_END | |
363 } | |
364 | |
365 STDMETHODIMP CHandler::Close() | |
366 { | |
367 m_Items.Clear(); | |
368 m_Archive.Close(); | |
369 return S_OK; | |
370 } | |
371 | |
372 ////////////////////////////////////// | |
373 // CHandler::DecompressItems | |
374 | |
375 class CLzmaDecoder: | |
376 public ICompressCoder, | |
377 public CMyUnknownImp | |
378 { | |
379 NCompress::NLzma::CDecoder *DecoderSpec; | |
380 CMyComPtr<ICompressCoder> Decoder; | |
381 public: | |
382 CLzmaDecoder(); | |
383 STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, | |
384 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); | |
385 | |
386 MY_UNKNOWN_IMP | |
387 }; | |
388 | |
389 CLzmaDecoder::CLzmaDecoder() | |
390 { | |
391 DecoderSpec = new NCompress::NLzma::CDecoder; | |
392 Decoder = DecoderSpec; | |
393 } | |
394 | |
395 HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, | |
396 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) | |
397 { | |
398 Byte buf[9]; | |
399 RINOK(ReadStream_FALSE(inStream, buf, 9)); | |
400 if (buf[2] != 5 || buf[3] != 0) | |
401 return E_NOTIMPL; | |
402 RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, 5)); | |
403 return Decoder->Code(inStream, outStream, NULL, outSize, progress); | |
404 } | |
405 | |
406 struct CMethodItem | |
407 { | |
408 UInt16 ZipMethod; | |
409 CMyComPtr<ICompressCoder> Coder; | |
410 }; | |
411 | |
412 class CZipDecoder | |
413 { | |
414 NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec; | |
415 NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec; | |
416 NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec; | |
417 | |
418 CMyComPtr<ICompressFilter> _zipCryptoDecoder; | |
419 CMyComPtr<ICompressFilter> _pkAesDecoder; | |
420 CMyComPtr<ICompressFilter> _wzAesDecoder; | |
421 | |
422 CFilterCoder *filterStreamSpec; | |
423 CMyComPtr<ISequentialInStream> filterStream; | |
424 CMyComPtr<ICryptoGetTextPassword> getTextPassword; | |
425 CObjectVector<CMethodItem> methodItems; | |
426 | |
427 public: | |
428 CZipDecoder(): | |
429 _zipCryptoDecoderSpec(0), | |
430 _pkAesDecoderSpec(0), | |
431 _wzAesDecoderSpec(0), | |
432 filterStreamSpec(0) {} | |
433 | |
434 HRESULT Decode( | |
435 DECL_EXTERNAL_CODECS_LOC_VARS | |
436 CInArchive &archive, const CItemEx &item, | |
437 ISequentialOutStream *realOutStream, | |
438 IArchiveExtractCallback *extractCallback, | |
439 ICompressProgressInfo *compressProgress, | |
440 UInt32 numThreads, Int32 &res); | |
441 }; | |
442 | |
443 HRESULT CZipDecoder::Decode( | |
444 DECL_EXTERNAL_CODECS_LOC_VARS | |
445 CInArchive &archive, const CItemEx &item, | |
446 ISequentialOutStream *realOutStream, | |
447 IArchiveExtractCallback *extractCallback, | |
448 ICompressProgressInfo *compressProgress, | |
449 UInt32 numThreads, Int32 &res) | |
450 { | |
451 res = NArchive::NExtract::NOperationResult::kDataError; | |
452 CInStreamReleaser inStreamReleaser; | |
453 | |
454 bool needCRC = true; | |
455 bool wzAesMode = false; | |
456 bool pkAesMode = false; | |
457 UInt16 methodId = item.CompressionMethod; | |
458 if (item.IsEncrypted()) | |
459 { | |
460 if (item.IsStrongEncrypted()) | |
461 { | |
462 CStrongCryptoField f; | |
463 if (item.CentralExtra.GetStrongCryptoField(f)) | |
464 { | |
465 pkAesMode = true; | |
466 } | |
467 if (!pkAesMode) | |
468 { | |
469 res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; | |
470 return S_OK; | |
471 } | |
472 } | |
473 if (methodId == NFileHeader::NCompressionMethod::kWzAES) | |
474 { | |
475 CWzAesExtraField aesField; | |
476 if (item.CentralExtra.GetWzAesField(aesField)) | |
477 { | |
478 wzAesMode = true; | |
479 needCRC = aesField.NeedCrc(); | |
480 } | |
481 } | |
482 } | |
483 | |
484 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; | |
485 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; | |
486 outStreamSpec->SetStream(realOutStream); | |
487 outStreamSpec->Init(needCRC); | |
488 | |
489 UInt64 authenticationPos; | |
490 | |
491 CMyComPtr<ISequentialInStream> inStream; | |
492 { | |
493 UInt64 packSize = item.PackSize; | |
494 if (wzAesMode) | |
495 { | |
496 if (packSize < NCrypto::NWzAes::kMacSize) | |
497 return S_OK; | |
498 packSize -= NCrypto::NWzAes::kMacSize; | |
499 } | |
500 UInt64 dataPos = item.GetDataPosition(); | |
501 inStream.Attach(archive.CreateLimitedStream(dataPos, packSize)); | |
502 authenticationPos = dataPos + packSize; | |
503 } | |
504 | |
505 CMyComPtr<ICompressFilter> cryptoFilter; | |
506 if (item.IsEncrypted()) | |
507 { | |
508 if (wzAesMode) | |
509 { | |
510 CWzAesExtraField aesField; | |
511 if (!item.CentralExtra.GetWzAesField(aesField)) | |
512 return S_OK; | |
513 methodId = aesField.Method; | |
514 if (!_wzAesDecoder) | |
515 { | |
516 _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder; | |
517 _wzAesDecoder = _wzAesDecoderSpec; | |
518 } | |
519 cryptoFilter = _wzAesDecoder; | |
520 Byte properties = aesField.Strength; | |
521 RINOK(_wzAesDecoderSpec->SetDecoderProperties2(&properties, 1)); | |
522 } | |
523 else if (pkAesMode) | |
524 { | |
525 if (!_pkAesDecoder) | |
526 { | |
527 _pkAesDecoderSpec = new NCrypto::NZipStrong::CDecoder; | |
528 _pkAesDecoder = _pkAesDecoderSpec; | |
529 } | |
530 cryptoFilter = _pkAesDecoder; | |
531 } | |
532 else | |
533 { | |
534 if (!_zipCryptoDecoder) | |
535 { | |
536 _zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder; | |
537 _zipCryptoDecoder = _zipCryptoDecoderSpec; | |
538 } | |
539 cryptoFilter = _zipCryptoDecoder; | |
540 } | |
541 CMyComPtr<ICryptoSetPassword> cryptoSetPassword; | |
542 RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); | |
543 | |
544 if (!getTextPassword) | |
545 extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); | |
546 | |
547 if (getTextPassword) | |
548 { | |
549 CMyComBSTR password; | |
550 RINOK(getTextPassword->CryptoGetTextPassword(&password)); | |
551 AString charPassword; | |
552 if (wzAesMode || pkAesMode) | |
553 { | |
554 charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP); | |
555 /* | |
556 for (int i = 0;; i++) | |
557 { | |
558 wchar_t c = password[i]; | |
559 if (c == 0) | |
560 break; | |
561 if (c >= 0x80) | |
562 { | |
563 res = NArchive::NExtract::NOperationResult::kDataError; | |
564 return S_OK; | |
565 } | |
566 charPassword += (char)c; | |
567 } | |
568 */ | |
569 } | |
570 else | |
571 { | |
572 // we use OEM. WinZip/Windows probably use ANSI for some files | |
573 charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP); | |
574 } | |
575 HRESULT result = cryptoSetPassword->CryptoSetPassword( | |
576 (const Byte *)(const char *)charPassword, charPassword.Length()); | |
577 if (result != S_OK) | |
578 return S_OK; | |
579 } | |
580 else | |
581 { | |
582 RINOK(cryptoSetPassword->CryptoSetPassword(0, 0)); | |
583 } | |
584 } | |
585 | |
586 int m; | |
587 for (m = 0; m < methodItems.Size(); m++) | |
588 if (methodItems[m].ZipMethod == methodId) | |
589 break; | |
590 | |
591 if (m == methodItems.Size()) | |
592 { | |
593 CMethodItem mi; | |
594 mi.ZipMethod = methodId; | |
595 if (methodId == NFileHeader::NCompressionMethod::kStored) | |
596 mi.Coder = new NCompress::CCopyCoder; | |
597 else if (methodId == NFileHeader::NCompressionMethod::kShrunk) | |
598 mi.Coder = new NCompress::NShrink::CDecoder; | |
599 else if (methodId == NFileHeader::NCompressionMethod::kImploded) | |
600 mi.Coder = new NCompress::NImplode::NDecoder::CCoder; | |
601 else if (methodId == NFileHeader::NCompressionMethod::kLZMA) | |
602 mi.Coder = new CLzmaDecoder; | |
603 else | |
604 { | |
605 CMethodId szMethodID; | |
606 if (methodId == NFileHeader::NCompressionMethod::kBZip2) | |
607 szMethodID = kMethodId_BZip2; | |
608 else | |
609 { | |
610 if (methodId > 0xFF) | |
611 { | |
612 res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; | |
613 return S_OK; | |
614 } | |
615 szMethodID = kMethodId_ZipBase + (Byte)methodId; | |
616 } | |
617 | |
618 RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false)); | |
619 | |
620 if (mi.Coder == 0) | |
621 { | |
622 res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; | |
623 return S_OK; | |
624 } | |
625 } | |
626 m = methodItems.Add(mi); | |
627 } | |
628 ICompressCoder *coder = methodItems[m].Coder; | |
629 | |
630 { | |
631 CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; | |
632 coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties); | |
633 if (setDecoderProperties) | |
634 { | |
635 Byte properties = (Byte)item.Flags; | |
636 RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1)); | |
637 } | |
638 } | |
639 | |
640 #ifdef COMPRESS_MT | |
641 { | |
642 CMyComPtr<ICompressSetCoderMt> setCoderMt; | |
643 coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); | |
644 if (setCoderMt) | |
645 { | |
646 RINOK(setCoderMt->SetNumberOfThreads(numThreads)); | |
647 } | |
648 } | |
649 #endif | |
650 | |
651 { | |
652 HRESULT result = S_OK; | |
653 CMyComPtr<ISequentialInStream> inStreamNew; | |
654 if (item.IsEncrypted()) | |
655 { | |
656 if (!filterStream) | |
657 { | |
658 filterStreamSpec = new CFilterCoder; | |
659 filterStream = filterStreamSpec; | |
660 } | |
661 filterStreamSpec->Filter = cryptoFilter; | |
662 if (wzAesMode) | |
663 { | |
664 result = _wzAesDecoderSpec->ReadHeader(inStream); | |
665 } | |
666 else if (pkAesMode) | |
667 { | |
668 result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize); | |
669 if (result == S_OK) | |
670 { | |
671 bool passwOK; | |
672 result = _pkAesDecoderSpec->CheckPassword(passwOK); | |
673 if (result == S_OK && !passwOK) | |
674 result = S_FALSE; | |
675 } | |
676 } | |
677 else | |
678 { | |
679 result = _zipCryptoDecoderSpec->ReadHeader(inStream); | |
680 } | |
681 | |
682 if (result == S_OK) | |
683 { | |
684 RINOK(filterStreamSpec->SetInStream(inStream)); | |
685 inStreamReleaser.FilterCoder = filterStreamSpec; | |
686 inStreamNew = filterStream; | |
687 if (wzAesMode) | |
688 { | |
689 if (!_wzAesDecoderSpec->CheckPasswordVerifyCode()) | |
690 result = S_FALSE; | |
691 } | |
692 } | |
693 } | |
694 else | |
695 inStreamNew = inStream; | |
696 if (result == S_OK) | |
697 result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress); | |
698 if (result == S_FALSE) | |
699 return S_OK; | |
700 if (result == E_NOTIMPL) | |
701 { | |
702 res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; | |
703 return S_OK; | |
704 } | |
705 | |
706 RINOK(result); | |
707 } | |
708 bool crcOK = true; | |
709 bool authOk = true; | |
710 if (needCRC) | |
711 crcOK = (outStreamSpec->GetCRC() == item.FileCRC); | |
712 if (wzAesMode) | |
713 { | |
714 inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize)); | |
715 if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK) | |
716 authOk = false; | |
717 } | |
718 | |
719 res = ((crcOK && authOk) ? | |
720 NArchive::NExtract::NOperationResult::kOK : | |
721 NArchive::NExtract::NOperationResult::kCRCError); | |
722 return S_OK; | |
723 } | |
724 | |
725 | |
726 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, | |
727 Int32 _aTestMode, IArchiveExtractCallback *extractCallback) | |
728 { | |
729 COM_TRY_BEGIN | |
730 CZipDecoder myDecoder; | |
731 bool testMode = (_aTestMode != 0); | |
732 UInt64 totalUnPacked = 0, totalPacked = 0; | |
733 bool allFilesMode = (numItems == UInt32(-1)); | |
734 if (allFilesMode) | |
735 numItems = m_Items.Size(); | |
736 if(numItems == 0) | |
737 return S_OK; | |
738 UInt32 i; | |
739 for(i = 0; i < numItems; i++) | |
740 { | |
741 const CItemEx &item = m_Items[allFilesMode ? i : indices[i]]; | |
742 totalUnPacked += item.UnPackSize; | |
743 totalPacked += item.PackSize; | |
744 } | |
745 RINOK(extractCallback->SetTotal(totalUnPacked)); | |
746 | |
747 UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0; | |
748 UInt64 currentItemUnPacked, currentItemPacked; | |
749 | |
750 CLocalProgress *lps = new CLocalProgress; | |
751 CMyComPtr<ICompressProgressInfo> progress = lps; | |
752 lps->Init(extractCallback, false); | |
753 | |
754 for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked, | |
755 currentTotalPacked += currentItemPacked) | |
756 { | |
757 currentItemUnPacked = 0; | |
758 currentItemPacked = 0; | |
759 | |
760 lps->InSize = currentTotalPacked; | |
761 lps->OutSize = currentTotalUnPacked; | |
762 RINOK(lps->SetCur()); | |
763 | |
764 CMyComPtr<ISequentialOutStream> realOutStream; | |
765 Int32 askMode = testMode ? | |
766 NArchive::NExtract::NAskMode::kTest : | |
767 NArchive::NExtract::NAskMode::kExtract; | |
768 Int32 index = allFilesMode ? i : indices[i]; | |
769 | |
770 RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); | |
771 | |
772 CItemEx item = m_Items[index]; | |
773 if (!item.FromLocal) | |
774 { | |
775 HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item); | |
776 if (res == S_FALSE) | |
777 { | |
778 if (item.IsDir() || realOutStream || testMode) | |
779 { | |
780 RINOK(extractCallback->PrepareOperation(askMode)); | |
781 realOutStream.Release(); | |
782 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod)); | |
783 } | |
784 continue; | |
785 } | |
786 RINOK(res); | |
787 } | |
788 | |
789 if (item.IsDir() || item.IgnoreItem()) | |
790 { | |
791 // if (!testMode) | |
792 { | |
793 RINOK(extractCallback->PrepareOperation(askMode)); | |
794 realOutStream.Release(); | |
795 RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); | |
796 } | |
797 continue; | |
798 } | |
799 | |
800 currentItemUnPacked = item.UnPackSize; | |
801 currentItemPacked = item.PackSize; | |
802 | |
803 if (!testMode && (!realOutStream)) | |
804 continue; | |
805 | |
806 RINOK(extractCallback->PrepareOperation(askMode)); | |
807 | |
808 #ifndef COMPRESS_MT | |
809 #define _numThreads 1 | |
810 #endif | |
811 | |
812 Int32 res; | |
813 RINOK(myDecoder.Decode( | |
814 EXTERNAL_CODECS_VARS | |
815 m_Archive, item, realOutStream, extractCallback, | |
816 progress, | |
817 _numThreads, | |
818 res)); | |
819 realOutStream.Release(); | |
820 | |
821 RINOK(extractCallback->SetOperationResult(res)) | |
822 } | |
823 return S_OK; | |
824 COM_TRY_END | |
825 } | |
826 | |
827 #ifndef EXTRACT_ONLY | |
828 IMPL_ISetCompressCodecsInfo | |
829 #endif | |
830 | |
831 }} |