5 #include "Common/ComTry.h"
\r
6 #include "Common/IntToString.h"
\r
8 #include "Windows/PropVariant.h"
\r
9 #include "Windows/Time.h"
\r
11 #include "../../IPassword.h"
\r
13 #include "../../Common/FilterCoder.h"
\r
14 #include "../../Common/ProgressUtils.h"
\r
15 #include "../../Common/StreamObjects.h"
\r
16 #include "../../Common/StreamUtils.h"
\r
18 #include "../../Compress/CopyCoder.h"
\r
19 #include "../../Compress/LzmaDecoder.h"
\r
20 #include "../../Compress/ImplodeDecoder.h"
\r
21 #include "../../Compress/PpmdZip.h"
\r
22 #include "../../Compress/ShrinkDecoder.h"
\r
24 #include "../../Crypto/WzAes.h"
\r
25 #include "../../Crypto/ZipCrypto.h"
\r
26 #include "../../Crypto/ZipStrong.h"
\r
28 #include "../Common/ItemNameUtils.h"
\r
29 #include "../Common/OutStreamWithCRC.h"
\r
31 #include "ZipHandler.h"
\r
33 using namespace NWindows;
\r
35 namespace NArchive {
\r
38 static const CMethodId kMethodId_ZipBase = 0x040100;
\r
39 static const CMethodId kMethodId_BZip2 = 0x040202;
\r
41 static const char *kHostOS[] =
\r
65 static const char *kUnknownOS = "Unknown";
\r
67 static const char *kMethods[] =
\r
82 static const char *kBZip2Method = "BZip2";
\r
83 static const char *kLZMAMethod = "LZMA";
\r
84 static const char *kJpegMethod = "Jpeg";
\r
85 static const char *kWavPackMethod = "WavPack";
\r
86 static const char *kPPMdMethod = "PPMd";
\r
87 static const char *kAESMethod = "AES";
\r
88 static const char *kZipCryptoMethod = "ZipCrypto";
\r
89 static const char *kStrongCryptoMethod = "StrongCrypto";
\r
91 static struct CStrongCryptoPair
\r
95 } g_StrongCryptoPairs[] =
\r
97 { NStrongCryptoFlags::kDES, "DES" },
\r
98 { NStrongCryptoFlags::kRC2old, "RC2a" },
\r
99 { NStrongCryptoFlags::k3DES168, "3DES-168" },
\r
100 { NStrongCryptoFlags::k3DES112, "3DES-112" },
\r
101 { NStrongCryptoFlags::kAES128, "pkAES-128" },
\r
102 { NStrongCryptoFlags::kAES192, "pkAES-192" },
\r
103 { NStrongCryptoFlags::kAES256, "pkAES-256" },
\r
104 { NStrongCryptoFlags::kRC2, "RC2" },
\r
105 { NStrongCryptoFlags::kBlowfish, "Blowfish" },
\r
106 { NStrongCryptoFlags::kTwofish, "Twofish" },
\r
107 { NStrongCryptoFlags::kRC4, "RC4" }
\r
110 static STATPROPSTG kProps[] =
\r
112 { NULL, kpidPath, VT_BSTR},
\r
113 { NULL, kpidIsDir, VT_BOOL},
\r
114 { NULL, kpidSize, VT_UI8},
\r
115 { NULL, kpidPackSize, VT_UI8},
\r
116 { NULL, kpidMTime, VT_FILETIME},
\r
117 { NULL, kpidCTime, VT_FILETIME},
\r
118 { NULL, kpidATime, VT_FILETIME},
\r
119 { NULL, kpidAttrib, VT_UI4},
\r
120 { NULL, kpidEncrypted, VT_BOOL},
\r
121 { NULL, kpidComment, VT_BSTR},
\r
122 { NULL, kpidCRC, VT_UI4},
\r
123 { NULL, kpidMethod, VT_BSTR},
\r
124 { NULL, kpidHostOS, VT_BSTR},
\r
125 { NULL, kpidUnpackVer, VT_UI4}
\r
128 static STATPROPSTG kArcProps[] =
\r
130 { NULL, kpidBit64, VT_BOOL},
\r
131 { NULL, kpidComment, VT_BSTR},
\r
132 { NULL, kpidPhySize, VT_UI8},
\r
133 { NULL, kpidOffset, VT_UI8}
\r
136 CHandler::CHandler()
\r
138 InitMethodProperties();
\r
141 static AString BytesToString(const CByteBuffer &data)
\r
144 int size = (int)data.GetCapacity();
\r
147 char *p = s.GetBuffer(size + 1);
\r
148 memcpy(p, (const Byte *)data, size);
\r
155 IMP_IInArchive_Props
\r
156 IMP_IInArchive_ArcProps
\r
158 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
\r
161 NWindows::NCOM::CPropVariant prop;
\r
164 case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break;
\r
165 case kpidComment: prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break;
\r
166 case kpidPhySize: prop = m_Archive.ArcInfo.GetPhySize(); break;
\r
167 case kpidOffset: if (m_Archive.ArcInfo.StartPosition != 0) prop = m_Archive.ArcInfo.StartPosition; break;
\r
169 prop.Detach(value);
\r
174 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
\r
176 *numItems = m_Items.Size();
\r
180 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
\r
183 NWindows::NCOM::CPropVariant prop;
\r
184 const CItemEx &item = m_Items[index];
\r
187 case kpidPath: prop = NItemName::GetOSName2(item.GetUnicodeString(item.Name)); break;
\r
188 case kpidIsDir: prop = item.IsDir(); break;
\r
189 case kpidSize: prop = item.UnPackSize; break;
\r
190 case kpidPackSize: prop = item.PackSize; break;
\r
195 if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
\r
196 prop = (UInt32)NFileTimeType::kWindows;
\r
197 else if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime))
\r
198 prop = (UInt32)NFileTimeType::kUnix;
\r
200 prop = (UInt32)NFileTimeType::kDOS;
\r
206 if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft))
\r
213 if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft))
\r
220 if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utc))
\r
223 if (item.CentralExtra.GetUnixTime(NFileHeader::NUnixTime::kMTime, unixTime))
\r
224 NTime::UnixTimeToFileTime(unixTime, utc);
\r
227 FILETIME localFileTime;
\r
228 if (!NTime::DosTimeToFileTime(item.Time, localFileTime) ||
\r
229 !LocalFileTimeToFileTime(&localFileTime, &utc))
\r
230 utc.dwHighDateTime = utc.dwLowDateTime = 0;
\r
236 case kpidAttrib: prop = item.GetWinAttributes(); break;
\r
237 case kpidEncrypted: prop = item.IsEncrypted(); break;
\r
238 case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break;
\r
239 case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break;
\r
242 UInt16 methodId = item.CompressionMethod;
\r
244 if (item.IsEncrypted())
\r
246 if (methodId == NFileHeader::NCompressionMethod::kWzAES)
\r
248 method = kAESMethod;
\r
249 CWzAesExtraField aesField;
\r
250 if (item.CentralExtra.GetWzAesField(aesField))
\r
254 ConvertUInt64ToString((aesField.Strength + 1) * 64 , s);
\r
257 methodId = aesField.Method;
\r
262 if (item.IsStrongEncrypted())
\r
264 CStrongCryptoField f;
\r
265 bool finded = false;
\r
266 if (item.CentralExtra.GetStrongCryptoField(f))
\r
268 for (int i = 0; i < sizeof(g_StrongCryptoPairs) / sizeof(g_StrongCryptoPairs[0]); i++)
\r
270 const CStrongCryptoPair &pair = g_StrongCryptoPairs[i];
\r
271 if (f.AlgId == pair.Id)
\r
273 method += pair.Name;
\r
280 method += kStrongCryptoMethod;
\r
283 method += kZipCryptoMethod;
\r
287 if (methodId < sizeof(kMethods) / sizeof(kMethods[0]))
\r
288 method += kMethods[methodId];
\r
289 else switch (methodId)
\r
291 case NFileHeader::NCompressionMethod::kLZMA:
\r
292 method += kLZMAMethod;
\r
293 if (item.IsLzmaEOS())
\r
296 case NFileHeader::NCompressionMethod::kBZip2: method += kBZip2Method; break;
\r
297 case NFileHeader::NCompressionMethod::kJpeg: method += kJpegMethod; break;
\r
298 case NFileHeader::NCompressionMethod::kWavPack: method += kWavPackMethod; break;
\r
299 case NFileHeader::NCompressionMethod::kPPMd: method += kPPMdMethod; break;
\r
303 ConvertUInt64ToString(methodId, s);
\r
311 prop = (item.MadeByVersion.HostOS < sizeof(kHostOS) / sizeof(kHostOS[0])) ?
\r
312 (kHostOS[item.MadeByVersion.HostOS]) : kUnknownOS;
\r
314 case kpidUnpackVer:
\r
315 prop = (UInt32)item.ExtractVersion.Version;
\r
318 prop.Detach(value);
\r
323 class CProgressImp: public CProgressVirt
\r
325 CMyComPtr<IArchiveOpenCallback> _callback;
\r
327 STDMETHOD(SetTotal)(UInt64 numFiles);
\r
328 STDMETHOD(SetCompleted)(UInt64 numFiles);
\r
329 CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {}
\r
332 STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles)
\r
335 return _callback->SetTotal(&numFiles, NULL);
\r
339 STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles)
\r
342 return _callback->SetCompleted(&numFiles, NULL);
\r
346 STDMETHODIMP CHandler::Open(IInStream *inStream,
\r
347 const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
\r
353 RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
\r
354 RINOK(m_Archive.Open(inStream, maxCheckStartPosition));
\r
355 CProgressImp progressImp(callback);
\r
356 return m_Archive.ReadHeaders(m_Items, &progressImp);
\r
358 catch(const CInArchiveException &) { Close(); return S_FALSE; }
\r
359 catch(...) { Close(); throw; }
\r
363 STDMETHODIMP CHandler::Close()
\r
370 //////////////////////////////////////
\r
371 // CHandler::DecompressItems
\r
373 class CLzmaDecoder:
\r
374 public ICompressCoder,
\r
375 public CMyUnknownImp
\r
377 NCompress::NLzma::CDecoder *DecoderSpec;
\r
378 CMyComPtr<ICompressCoder> Decoder;
\r
381 STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
382 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
\r
387 CLzmaDecoder::CLzmaDecoder()
\r
389 DecoderSpec = new NCompress::NLzma::CDecoder;
\r
390 Decoder = DecoderSpec;
\r
393 HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
394 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
\r
397 RINOK(ReadStream_FALSE(inStream, buf, 9));
\r
398 if (buf[2] != 5 || buf[3] != 0)
\r
400 RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, 5));
\r
401 return Decoder->Code(inStream, outStream, NULL, outSize, progress);
\r
407 CMyComPtr<ICompressCoder> Coder;
\r
412 NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec;
\r
413 NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec;
\r
414 NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec;
\r
416 CMyComPtr<ICompressFilter> _zipCryptoDecoder;
\r
417 CMyComPtr<ICompressFilter> _pkAesDecoder;
\r
418 CMyComPtr<ICompressFilter> _wzAesDecoder;
\r
420 CFilterCoder *filterStreamSpec;
\r
421 CMyComPtr<ISequentialInStream> filterStream;
\r
422 CMyComPtr<ICryptoGetTextPassword> getTextPassword;
\r
423 CObjectVector<CMethodItem> methodItems;
\r
427 _zipCryptoDecoderSpec(0),
\r
428 _pkAesDecoderSpec(0),
\r
429 _wzAesDecoderSpec(0),
\r
430 filterStreamSpec(0) {}
\r
433 DECL_EXTERNAL_CODECS_LOC_VARS
\r
434 CInArchive &archive, const CItemEx &item,
\r
435 ISequentialOutStream *realOutStream,
\r
436 IArchiveExtractCallback *extractCallback,
\r
437 ICompressProgressInfo *compressProgress,
\r
438 UInt32 numThreads, Int32 &res);
\r
441 HRESULT CZipDecoder::Decode(
\r
442 DECL_EXTERNAL_CODECS_LOC_VARS
\r
443 CInArchive &archive, const CItemEx &item,
\r
444 ISequentialOutStream *realOutStream,
\r
445 IArchiveExtractCallback *extractCallback,
\r
446 ICompressProgressInfo *compressProgress,
\r
447 UInt32 numThreads, Int32 &res)
\r
449 res = NExtract::NOperationResult::kDataError;
\r
450 CInStreamReleaser inStreamReleaser;
\r
452 bool needCRC = true;
\r
453 bool wzAesMode = false;
\r
454 bool pkAesMode = false;
\r
455 UInt16 methodId = item.CompressionMethod;
\r
456 if (item.IsEncrypted())
\r
458 if (item.IsStrongEncrypted())
\r
460 CStrongCryptoField f;
\r
461 if (item.CentralExtra.GetStrongCryptoField(f))
\r
467 res = NExtract::NOperationResult::kUnSupportedMethod;
\r
471 if (methodId == NFileHeader::NCompressionMethod::kWzAES)
\r
473 CWzAesExtraField aesField;
\r
474 if (item.CentralExtra.GetWzAesField(aesField))
\r
477 needCRC = aesField.NeedCrc();
\r
482 COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
\r
483 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
\r
484 outStreamSpec->SetStream(realOutStream);
\r
485 outStreamSpec->Init(needCRC);
\r
487 UInt64 authenticationPos;
\r
489 CMyComPtr<ISequentialInStream> inStream;
\r
491 UInt64 packSize = item.PackSize;
\r
494 if (packSize < NCrypto::NWzAes::kMacSize)
\r
496 packSize -= NCrypto::NWzAes::kMacSize;
\r
498 UInt64 dataPos = item.GetDataPosition();
\r
499 inStream.Attach(archive.CreateLimitedStream(dataPos, packSize));
\r
500 authenticationPos = dataPos + packSize;
\r
503 CMyComPtr<ICompressFilter> cryptoFilter;
\r
504 if (item.IsEncrypted())
\r
508 CWzAesExtraField aesField;
\r
509 if (!item.CentralExtra.GetWzAesField(aesField))
\r
511 methodId = aesField.Method;
\r
512 if (!_wzAesDecoder)
\r
514 _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder;
\r
515 _wzAesDecoder = _wzAesDecoderSpec;
\r
517 cryptoFilter = _wzAesDecoder;
\r
518 Byte properties = aesField.Strength;
\r
519 RINOK(_wzAesDecoderSpec->SetDecoderProperties2(&properties, 1));
\r
521 else if (pkAesMode)
\r
523 if (!_pkAesDecoder)
\r
525 _pkAesDecoderSpec = new NCrypto::NZipStrong::CDecoder;
\r
526 _pkAesDecoder = _pkAesDecoderSpec;
\r
528 cryptoFilter = _pkAesDecoder;
\r
532 if (!_zipCryptoDecoder)
\r
534 _zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder;
\r
535 _zipCryptoDecoder = _zipCryptoDecoderSpec;
\r
537 cryptoFilter = _zipCryptoDecoder;
\r
539 CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
\r
540 RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
\r
542 if (!getTextPassword)
\r
543 extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
\r
545 if (getTextPassword)
\r
547 CMyComBSTR password;
\r
548 RINOK(getTextPassword->CryptoGetTextPassword(&password));
\r
549 AString charPassword;
\r
550 if (wzAesMode || pkAesMode)
\r
552 charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP);
\r
554 for (int i = 0;; i++)
\r
556 wchar_t c = password[i];
\r
561 res = NExtract::NOperationResult::kDataError;
\r
564 charPassword += (char)c;
\r
570 // we use OEM. WinZip/Windows probably use ANSI for some files
\r
571 charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP);
\r
573 HRESULT result = cryptoSetPassword->CryptoSetPassword(
\r
574 (const Byte *)(const char *)charPassword, charPassword.Length());
\r
575 if (result != S_OK)
\r
580 RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
\r
585 for (m = 0; m < methodItems.Size(); m++)
\r
586 if (methodItems[m].ZipMethod == methodId)
\r
589 if (m == methodItems.Size())
\r
592 mi.ZipMethod = methodId;
\r
593 if (methodId == NFileHeader::NCompressionMethod::kStored)
\r
594 mi.Coder = new NCompress::CCopyCoder;
\r
595 else if (methodId == NFileHeader::NCompressionMethod::kShrunk)
\r
596 mi.Coder = new NCompress::NShrink::CDecoder;
\r
597 else if (methodId == NFileHeader::NCompressionMethod::kImploded)
\r
598 mi.Coder = new NCompress::NImplode::NDecoder::CCoder;
\r
599 else if (methodId == NFileHeader::NCompressionMethod::kLZMA)
\r
600 mi.Coder = new CLzmaDecoder;
\r
601 else if (methodId == NFileHeader::NCompressionMethod::kPPMd)
\r
602 mi.Coder = new NCompress::NPpmdZip::CDecoder(true);
\r
605 CMethodId szMethodID;
\r
606 if (methodId == NFileHeader::NCompressionMethod::kBZip2)
\r
607 szMethodID = kMethodId_BZip2;
\r
610 if (methodId > 0xFF)
\r
612 res = NExtract::NOperationResult::kUnSupportedMethod;
\r
615 szMethodID = kMethodId_ZipBase + (Byte)methodId;
\r
618 RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false));
\r
622 res = NExtract::NOperationResult::kUnSupportedMethod;
\r
626 m = methodItems.Add(mi);
\r
628 ICompressCoder *coder = methodItems[m].Coder;
\r
631 CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
\r
632 coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);
\r
633 if (setDecoderProperties)
\r
635 Byte properties = (Byte)item.Flags;
\r
636 RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1));
\r
642 CMyComPtr<ICompressSetCoderMt> setCoderMt;
\r
643 coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
\r
646 RINOK(setCoderMt->SetNumberOfThreads(numThreads));
\r
652 HRESULT result = S_OK;
\r
653 CMyComPtr<ISequentialInStream> inStreamNew;
\r
654 if (item.IsEncrypted())
\r
658 filterStreamSpec = new CFilterCoder;
\r
659 filterStream = filterStreamSpec;
\r
661 filterStreamSpec->Filter = cryptoFilter;
\r
664 result = _wzAesDecoderSpec->ReadHeader(inStream);
\r
666 else if (pkAesMode)
\r
668 result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize);
\r
669 if (result == S_OK)
\r
672 result = _pkAesDecoderSpec->CheckPassword(passwOK);
\r
673 if (result == S_OK && !passwOK)
\r
679 result = _zipCryptoDecoderSpec->ReadHeader(inStream);
\r
682 if (result == S_OK)
\r
684 RINOK(filterStreamSpec->SetInStream(inStream));
\r
685 inStreamReleaser.FilterCoder = filterStreamSpec;
\r
686 inStreamNew = filterStream;
\r
689 if (!_wzAesDecoderSpec->CheckPasswordVerifyCode())
\r
695 inStreamNew = inStream;
\r
696 if (result == S_OK)
\r
697 result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress);
\r
698 if (result == S_FALSE)
\r
700 if (result == E_NOTIMPL)
\r
702 res = NExtract::NOperationResult::kUnSupportedMethod;
\r
709 bool authOk = true;
\r
711 crcOK = (outStreamSpec->GetCRC() == item.FileCRC);
\r
714 inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize));
\r
715 if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
\r
719 res = ((crcOK && authOk) ?
\r
720 NExtract::NOperationResult::kOK :
\r
721 NExtract::NOperationResult::kCRCError);
\r
726 STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
\r
727 Int32 testMode, IArchiveExtractCallback *extractCallback)
\r
730 CZipDecoder myDecoder;
\r
731 UInt64 totalUnPacked = 0, totalPacked = 0;
\r
732 bool allFilesMode = (numItems == (UInt32)-1);
\r
734 numItems = m_Items.Size();
\r
738 for (i = 0; i < numItems; i++)
\r
740 const CItemEx &item = m_Items[allFilesMode ? i : indices[i]];
\r
741 totalUnPacked += item.UnPackSize;
\r
742 totalPacked += item.PackSize;
\r
744 RINOK(extractCallback->SetTotal(totalUnPacked));
\r
746 UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0;
\r
747 UInt64 currentItemUnPacked, currentItemPacked;
\r
749 CLocalProgress *lps = new CLocalProgress;
\r
750 CMyComPtr<ICompressProgressInfo> progress = lps;
\r
751 lps->Init(extractCallback, false);
\r
753 for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked,
\r
754 currentTotalPacked += currentItemPacked)
\r
756 currentItemUnPacked = 0;
\r
757 currentItemPacked = 0;
\r
759 lps->InSize = currentTotalPacked;
\r
760 lps->OutSize = currentTotalUnPacked;
\r
761 RINOK(lps->SetCur());
\r
763 CMyComPtr<ISequentialOutStream> realOutStream;
\r
764 Int32 askMode = testMode ?
\r
765 NExtract::NAskMode::kTest :
\r
766 NExtract::NAskMode::kExtract;
\r
767 Int32 index = allFilesMode ? i : indices[i];
\r
769 RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
\r
771 CItemEx item = m_Items[index];
\r
772 if (!item.FromLocal)
\r
774 HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item);
\r
775 if (res == S_FALSE)
\r
777 if (item.IsDir() || realOutStream || testMode)
\r
779 RINOK(extractCallback->PrepareOperation(askMode));
\r
780 realOutStream.Release();
\r
781 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod));
\r
788 if (item.IsDir() || item.IgnoreItem())
\r
792 RINOK(extractCallback->PrepareOperation(askMode));
\r
793 realOutStream.Release();
\r
794 RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK));
\r
799 currentItemUnPacked = item.UnPackSize;
\r
800 currentItemPacked = item.PackSize;
\r
802 if (!testMode && !realOutStream)
\r
805 RINOK(extractCallback->PrepareOperation(askMode));
\r
808 RINOK(myDecoder.Decode(
\r
809 EXTERNAL_CODECS_VARS
\r
810 m_Archive, item, realOutStream, extractCallback,
\r
811 progress, _numThreads, res));
\r
812 realOutStream.Release();
\r
814 RINOK(extractCallback->SetOperationResult(res))
\r
820 IMPL_ISetCompressCodecsInfo
\r