view 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
line wrap: on
line source
1 // ZipHandler.cpp
3 #include "StdAfx.h"
5 #include "Common/ComTry.h"
6 #include "Common/Defs.h"
7 #include "Common/IntToString.h"
8 #include "Common/StringConvert.h"
10 #include "Windows/PropVariant.h"
11 #include "Windows/Time.h"
13 #include "../../IPassword.h"
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"
21 #include "../../Compress/CopyCoder.h"
22 #include "../../Compress/LzmaDecoder.h"
23 #include "../../Compress/ImplodeDecoder.h"
24 #include "../../Compress/ShrinkDecoder.h"
26 #include "../../Crypto/WzAes.h"
27 #include "../../Crypto/ZipCrypto.h"
28 #include "../../Crypto/ZipStrong.h"
30 #include "../Common/ItemNameUtils.h"
31 #include "../Common/OutStreamWithCRC.h"
33 #include "ZipHandler.h"
35 using namespace NWindows;
37 namespace NArchive {
38 namespace NZip {
40 // static const CMethodId kMethodId_Store = 0;
41 static const CMethodId kMethodId_ZipBase = 0x040100;
42 static const CMethodId kMethodId_BZip2 = 0x040202;
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 };
69 static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
71 static const wchar_t *kUnknownOS = L"Unknown";
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},
83 { NULL, kpidAttrib, VT_UI4},
85 { NULL, kpidEncrypted, VT_BOOL},
86 { NULL, kpidComment, VT_BSTR},
88 { NULL, kpidCRC, VT_UI4},
90 { NULL, kpidMethod, VT_BSTR},
91 { NULL, kpidHostOS, VT_BSTR}
93 // { NULL, kpidUnpackVer, VT_UI1},
94 };
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 };
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";
121 struct CStrongCryptoPair
122 {
123 UInt16 Id;
124 const wchar_t *Name;
125 };
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 };
142 STATPROPSTG kArcProps[] =
143 {
144 { NULL, kpidBit64, VT_BOOL},
145 { NULL, kpidComment, VT_BSTR}
146 };
148 CHandler::CHandler()
149 {
150 InitMethodProperties();
151 }
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 }
167 IMP_IInArchive_Props
168 IMP_IInArchive_ArcProps
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 }
186 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
187 {
188 *numItems = m_Items.Size();
189 return S_OK;
190 }
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 }
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 };
334 STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles)
335 {
336 if (_callback)
337 return _callback->SetTotal(&numFiles, NULL);
338 return S_OK;
339 }
341 STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles)
342 {
343 if (_callback)
344 return _callback->SetCompleted(&numFiles, NULL);
345 return S_OK;
346 }
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 }
365 STDMETHODIMP CHandler::Close()
366 {
367 m_Items.Clear();
368 m_Archive.Close();
369 return S_OK;
370 }
372 //////////////////////////////////////
373 // CHandler::DecompressItems
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);
386 MY_UNKNOWN_IMP
387 };
389 CLzmaDecoder::CLzmaDecoder()
390 {
391 DecoderSpec = new NCompress::NLzma::CDecoder;
392 Decoder = DecoderSpec;
393 }
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 }
406 struct CMethodItem
407 {
408 UInt16 ZipMethod;
409 CMyComPtr<ICompressCoder> Coder;
410 };
412 class CZipDecoder
413 {
414 NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec;
415 NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec;
416 NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec;
418 CMyComPtr<ICompressFilter> _zipCryptoDecoder;
419 CMyComPtr<ICompressFilter> _pkAesDecoder;
420 CMyComPtr<ICompressFilter> _wzAesDecoder;
422 CFilterCoder *filterStreamSpec;
423 CMyComPtr<ISequentialInStream> filterStream;
424 CMyComPtr<ICryptoGetTextPassword> getTextPassword;
425 CObjectVector<CMethodItem> methodItems;
427 public:
428 CZipDecoder():
429 _zipCryptoDecoderSpec(0),
430 _pkAesDecoderSpec(0),
431 _wzAesDecoderSpec(0),
432 filterStreamSpec(0) {}
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 };
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;
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 }
484 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
485 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
486 outStreamSpec->SetStream(realOutStream);
487 outStreamSpec->Init(needCRC);
489 UInt64 authenticationPos;
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 }
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));
544 if (!getTextPassword)
545 extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
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 }
586 int m;
587 for (m = 0; m < methodItems.Size(); m++)
588 if (methodItems[m].ZipMethod == methodId)
589 break;
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 }
618 RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false));
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;
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 }
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
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 }
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 }
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 }
719 res = ((crcOK && authOk) ?
720 NArchive::NExtract::NOperationResult::kOK :
721 NArchive::NExtract::NOperationResult::kCRCError);
722 return S_OK;
723 }
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));
747 UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
748 UInt64 currentItemUnPacked, currentItemPacked;
750 CLocalProgress *lps = new CLocalProgress;
751 CMyComPtr<ICompressProgressInfo> progress = lps;
752 lps->Init(extractCallback, false);
754 for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
755 currentTotalPacked += currentItemPacked)
756 {
757 currentItemUnPacked = 0;
758 currentItemPacked = 0;
760 lps->InSize = currentTotalPacked;
761 lps->OutSize = currentTotalUnPacked;
762 RINOK(lps->SetCur());
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];
770 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
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 }
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 }
800 currentItemUnPacked = item.UnPackSize;
801 currentItemPacked = item.PackSize;
803 if (!testMode && (!realOutStream))
804 continue;
806 RINOK(extractCallback->PrepareOperation(askMode));
808 #ifndef COMPRESS_MT
809 #define _numThreads 1
810 #endif
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();
821 RINOK(extractCallback->SetOperationResult(res))
822 }
823 return S_OK;
824 COM_TRY_END
825 }
827 #ifndef EXTRACT_ONLY
828 IMPL_ISetCompressCodecsInfo
829 #endif
831 }}