Mercurial > vba-linux
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/win32/7zip/7z/CPP/7zip/Archive/Zip/ZipHandler.cpp Sat Mar 03 10:31:27 2012 -0600 1.3 @@ -0,0 +1,831 @@ 1.4 +// ZipHandler.cpp 1.5 + 1.6 +#include "StdAfx.h" 1.7 + 1.8 +#include "Common/ComTry.h" 1.9 +#include "Common/Defs.h" 1.10 +#include "Common/IntToString.h" 1.11 +#include "Common/StringConvert.h" 1.12 + 1.13 +#include "Windows/PropVariant.h" 1.14 +#include "Windows/Time.h" 1.15 + 1.16 +#include "../../IPassword.h" 1.17 + 1.18 +#include "../../Common/CreateCoder.h" 1.19 +#include "../../Common/FilterCoder.h" 1.20 +#include "../../Common/ProgressUtils.h" 1.21 +#include "../../Common/StreamObjects.h" 1.22 +#include "../../Common/StreamUtils.h" 1.23 + 1.24 +#include "../../Compress/CopyCoder.h" 1.25 +#include "../../Compress/LzmaDecoder.h" 1.26 +#include "../../Compress/ImplodeDecoder.h" 1.27 +#include "../../Compress/ShrinkDecoder.h" 1.28 + 1.29 +#include "../../Crypto/WzAes.h" 1.30 +#include "../../Crypto/ZipCrypto.h" 1.31 +#include "../../Crypto/ZipStrong.h" 1.32 + 1.33 +#include "../Common/ItemNameUtils.h" 1.34 +#include "../Common/OutStreamWithCRC.h" 1.35 + 1.36 +#include "ZipHandler.h" 1.37 + 1.38 +using namespace NWindows; 1.39 + 1.40 +namespace NArchive { 1.41 +namespace NZip { 1.42 + 1.43 +// static const CMethodId kMethodId_Store = 0; 1.44 +static const CMethodId kMethodId_ZipBase = 0x040100; 1.45 +static const CMethodId kMethodId_BZip2 = 0x040202; 1.46 + 1.47 +const wchar_t *kHostOS[] = 1.48 +{ 1.49 + L"FAT", 1.50 + L"AMIGA", 1.51 + L"VMS", 1.52 + L"Unix", 1.53 + L"VM/CMS", 1.54 + L"Atari", 1.55 + L"HPFS", 1.56 + L"Macintosh", 1.57 + L"Z-System", 1.58 + L"CP/M", 1.59 + L"TOPS-20", 1.60 + L"NTFS", 1.61 + L"SMS/QDOS", 1.62 + L"Acorn", 1.63 + L"VFAT", 1.64 + L"MVS", 1.65 + L"BeOS", 1.66 + L"Tandem", 1.67 + L"OS/400", 1.68 + L"OS/X" 1.69 +}; 1.70 + 1.71 + 1.72 +static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]); 1.73 + 1.74 +static const wchar_t *kUnknownOS = L"Unknown"; 1.75 + 1.76 +STATPROPSTG kProps[] = 1.77 +{ 1.78 + { NULL, kpidPath, VT_BSTR}, 1.79 + { NULL, kpidIsDir, VT_BOOL}, 1.80 + { NULL, kpidSize, VT_UI8}, 1.81 + { NULL, kpidPackSize, VT_UI8}, 1.82 + { NULL, kpidMTime, VT_FILETIME}, 1.83 + { NULL, kpidCTime, VT_FILETIME}, 1.84 + { NULL, kpidATime, VT_FILETIME}, 1.85 + 1.86 + { NULL, kpidAttrib, VT_UI4}, 1.87 + 1.88 + { NULL, kpidEncrypted, VT_BOOL}, 1.89 + { NULL, kpidComment, VT_BSTR}, 1.90 + 1.91 + { NULL, kpidCRC, VT_UI4}, 1.92 + 1.93 + { NULL, kpidMethod, VT_BSTR}, 1.94 + { NULL, kpidHostOS, VT_BSTR} 1.95 + 1.96 + // { NULL, kpidUnpackVer, VT_UI1}, 1.97 +}; 1.98 + 1.99 +const wchar_t *kMethods[] = 1.100 +{ 1.101 + L"Store", 1.102 + L"Shrink", 1.103 + L"Reduced1", 1.104 + L"Reduced2", 1.105 + L"Reduced2", 1.106 + L"Reduced3", 1.107 + L"Implode", 1.108 + L"Tokenizing", 1.109 + L"Deflate", 1.110 + L"Deflate64", 1.111 + L"PKImploding" 1.112 +}; 1.113 + 1.114 +const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]); 1.115 +const wchar_t *kBZip2Method = L"BZip2"; 1.116 +const wchar_t *kLZMAMethod = L"LZMA"; 1.117 +const wchar_t *kJpegMethod = L"Jpeg"; 1.118 +const wchar_t *kWavPackMethod = L"WavPack"; 1.119 +const wchar_t *kPPMdMethod = L"PPMd"; 1.120 +const wchar_t *kAESMethod = L"AES"; 1.121 +const wchar_t *kZipCryptoMethod = L"ZipCrypto"; 1.122 +const wchar_t *kStrongCryptoMethod = L"StrongCrypto"; 1.123 + 1.124 +struct CStrongCryptoPair 1.125 +{ 1.126 + UInt16 Id; 1.127 + const wchar_t *Name; 1.128 +}; 1.129 + 1.130 +CStrongCryptoPair g_StrongCryptoPairs[] = 1.131 +{ 1.132 + { NStrongCryptoFlags::kDES, L"DES" }, 1.133 + { NStrongCryptoFlags::kRC2old, L"RC2a" }, 1.134 + { NStrongCryptoFlags::k3DES168, L"3DES-168" }, 1.135 + { NStrongCryptoFlags::k3DES112, L"3DES-112" }, 1.136 + { NStrongCryptoFlags::kAES128, L"pkAES-128" }, 1.137 + { NStrongCryptoFlags::kAES192, L"pkAES-192" }, 1.138 + { NStrongCryptoFlags::kAES256, L"pkAES-256" }, 1.139 + { NStrongCryptoFlags::kRC2, L"RC2" }, 1.140 + { NStrongCryptoFlags::kBlowfish, L"Blowfish" }, 1.141 + { NStrongCryptoFlags::kTwofish, L"Twofish" }, 1.142 + { NStrongCryptoFlags::kRC4, L"RC4" } 1.143 +}; 1.144 + 1.145 +STATPROPSTG kArcProps[] = 1.146 +{ 1.147 + { NULL, kpidBit64, VT_BOOL}, 1.148 + { NULL, kpidComment, VT_BSTR} 1.149 +}; 1.150 + 1.151 +CHandler::CHandler() 1.152 +{ 1.153 + InitMethodProperties(); 1.154 +} 1.155 + 1.156 +static AString BytesToString(const CByteBuffer &data) 1.157 +{ 1.158 + AString s; 1.159 + int size = (int)data.GetCapacity(); 1.160 + if (size > 0) 1.161 + { 1.162 + char *p = s.GetBuffer(size + 1); 1.163 + memcpy(p, (const Byte *)data, size); 1.164 + p[size] = '\0'; 1.165 + s.ReleaseBuffer(); 1.166 + } 1.167 + return s; 1.168 +} 1.169 + 1.170 +IMP_IInArchive_Props 1.171 +IMP_IInArchive_ArcProps 1.172 + 1.173 +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) 1.174 +{ 1.175 + COM_TRY_BEGIN 1.176 + NWindows::NCOM::CPropVariant prop; 1.177 + switch(propID) 1.178 + { 1.179 + case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break; 1.180 + case kpidComment: 1.181 + prop = MultiByteToUnicodeString(BytesToString(m_Archive.m_ArchiveInfo.Comment), CP_ACP); 1.182 + break; 1.183 + } 1.184 + prop.Detach(value); 1.185 + COM_TRY_END 1.186 + return S_OK; 1.187 +} 1.188 + 1.189 +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) 1.190 +{ 1.191 + *numItems = m_Items.Size(); 1.192 + return S_OK; 1.193 +} 1.194 + 1.195 +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) 1.196 +{ 1.197 + COM_TRY_BEGIN 1.198 + NWindows::NCOM::CPropVariant prop; 1.199 + const CItemEx &item = m_Items[index]; 1.200 + switch(propID) 1.201 + { 1.202 + case kpidPath: prop = NItemName::GetOSName2(item.GetUnicodeString(item.Name)); break; 1.203 + case kpidIsDir: prop = item.IsDir(); break; 1.204 + case kpidSize: prop = item.UnPackSize; break; 1.205 + case kpidPackSize: prop = item.PackSize; break; 1.206 + case kpidTimeType: 1.207 + { 1.208 + FILETIME utcFileTime; 1.209 + if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kTagTime, utcFileTime)) 1.210 + prop = (UInt32)NFileTimeType::kWindows; 1.211 + break; 1.212 + } 1.213 + case kpidCTime: 1.214 + { 1.215 + FILETIME ft; 1.216 + if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kCTime, ft)) 1.217 + prop = ft; 1.218 + break; 1.219 + } 1.220 + case kpidATime: 1.221 + { 1.222 + FILETIME ft; 1.223 + if (item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kATime, ft)) 1.224 + prop = ft; 1.225 + break; 1.226 + } 1.227 + case kpidMTime: 1.228 + { 1.229 + FILETIME utcFileTime; 1.230 + if (!item.CentralExtra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, utcFileTime)) 1.231 + { 1.232 + FILETIME localFileTime; 1.233 + if (NTime::DosTimeToFileTime(item.Time, localFileTime)) 1.234 + { 1.235 + if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime)) 1.236 + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; 1.237 + } 1.238 + else 1.239 + utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0; 1.240 + } 1.241 + prop = utcFileTime; 1.242 + break; 1.243 + } 1.244 + case kpidAttrib: prop = item.GetWinAttributes(); break; 1.245 + case kpidEncrypted: prop = item.IsEncrypted(); break; 1.246 + case kpidComment: prop = item.GetUnicodeString(BytesToString(item.Comment)); break; 1.247 + case kpidCRC: if (item.IsThereCrc()) prop = item.FileCRC; break; 1.248 + case kpidMethod: 1.249 + { 1.250 + UInt16 methodId = item.CompressionMethod; 1.251 + UString method; 1.252 + if (item.IsEncrypted()) 1.253 + { 1.254 + if (methodId == NFileHeader::NCompressionMethod::kWzAES) 1.255 + { 1.256 + method = kAESMethod; 1.257 + CWzAesExtraField aesField; 1.258 + if (item.CentralExtra.GetWzAesField(aesField)) 1.259 + { 1.260 + method += L"-"; 1.261 + wchar_t s[32]; 1.262 + ConvertUInt64ToString((aesField.Strength + 1) * 64 , s); 1.263 + method += s; 1.264 + method += L" "; 1.265 + methodId = aesField.Method; 1.266 + } 1.267 + } 1.268 + else 1.269 + { 1.270 + if (item.IsStrongEncrypted()) 1.271 + { 1.272 + CStrongCryptoField f; 1.273 + bool finded = false; 1.274 + if (item.CentralExtra.GetStrongCryptoField(f)) 1.275 + { 1.276 + for (int i = 0; i < sizeof(g_StrongCryptoPairs) / sizeof(g_StrongCryptoPairs[0]); i++) 1.277 + { 1.278 + const CStrongCryptoPair &pair = g_StrongCryptoPairs[i]; 1.279 + if (f.AlgId == pair.Id) 1.280 + { 1.281 + method += pair.Name; 1.282 + finded = true; 1.283 + break; 1.284 + } 1.285 + } 1.286 + } 1.287 + if (!finded) 1.288 + method += kStrongCryptoMethod; 1.289 + } 1.290 + else 1.291 + method += kZipCryptoMethod; 1.292 + method += L" "; 1.293 + } 1.294 + } 1.295 + if (methodId < kNumMethods) 1.296 + method += kMethods[methodId]; 1.297 + else switch (methodId) 1.298 + { 1.299 + case NFileHeader::NCompressionMethod::kLZMA: 1.300 + method += kLZMAMethod; 1.301 + if (item.IsLzmaEOS()) 1.302 + method += L":EOS"; 1.303 + break; 1.304 + case NFileHeader::NCompressionMethod::kBZip2: method += kBZip2Method; break; 1.305 + case NFileHeader::NCompressionMethod::kJpeg: method += kJpegMethod; break; 1.306 + case NFileHeader::NCompressionMethod::kWavPack: method += kWavPackMethod; break; 1.307 + case NFileHeader::NCompressionMethod::kPPMd: method += kPPMdMethod; break; 1.308 + default: 1.309 + { 1.310 + wchar_t s[32]; 1.311 + ConvertUInt64ToString(methodId, s); 1.312 + method += s; 1.313 + } 1.314 + } 1.315 + prop = method; 1.316 + break; 1.317 + } 1.318 + case kpidHostOS: 1.319 + prop = (item.MadeByVersion.HostOS < kNumHostOSes) ? 1.320 + (kHostOS[item.MadeByVersion.HostOS]) : kUnknownOS; 1.321 + break; 1.322 + } 1.323 + prop.Detach(value); 1.324 + return S_OK; 1.325 + COM_TRY_END 1.326 +} 1.327 + 1.328 +class CProgressImp: public CProgressVirt 1.329 +{ 1.330 + CMyComPtr<IArchiveOpenCallback> _callback; 1.331 +public: 1.332 + STDMETHOD(SetTotal)(UInt64 numFiles); 1.333 + STDMETHOD(SetCompleted)(UInt64 numFiles); 1.334 + CProgressImp(IArchiveOpenCallback *callback): _callback(callback) {} 1.335 +}; 1.336 + 1.337 +STDMETHODIMP CProgressImp::SetTotal(UInt64 numFiles) 1.338 +{ 1.339 + if (_callback) 1.340 + return _callback->SetTotal(&numFiles, NULL); 1.341 + return S_OK; 1.342 +} 1.343 + 1.344 +STDMETHODIMP CProgressImp::SetCompleted(UInt64 numFiles) 1.345 +{ 1.346 + if (_callback) 1.347 + return _callback->SetCompleted(&numFiles, NULL); 1.348 + return S_OK; 1.349 +} 1.350 + 1.351 +STDMETHODIMP CHandler::Open(IInStream *inStream, 1.352 + const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) 1.353 +{ 1.354 + COM_TRY_BEGIN 1.355 + try 1.356 + { 1.357 + Close(); 1.358 + RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); 1.359 + RINOK(m_Archive.Open(inStream, maxCheckStartPosition)); 1.360 + CProgressImp progressImp(callback); 1.361 + return m_Archive.ReadHeaders(m_Items, &progressImp); 1.362 + } 1.363 + catch(const CInArchiveException &) { Close(); return S_FALSE; } 1.364 + catch(...) { Close(); throw; } 1.365 + COM_TRY_END 1.366 +} 1.367 + 1.368 +STDMETHODIMP CHandler::Close() 1.369 +{ 1.370 + m_Items.Clear(); 1.371 + m_Archive.Close(); 1.372 + return S_OK; 1.373 +} 1.374 + 1.375 +////////////////////////////////////// 1.376 +// CHandler::DecompressItems 1.377 + 1.378 +class CLzmaDecoder: 1.379 + public ICompressCoder, 1.380 + public CMyUnknownImp 1.381 +{ 1.382 + NCompress::NLzma::CDecoder *DecoderSpec; 1.383 + CMyComPtr<ICompressCoder> Decoder; 1.384 +public: 1.385 + CLzmaDecoder(); 1.386 + STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream, 1.387 + const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress); 1.388 + 1.389 + MY_UNKNOWN_IMP 1.390 +}; 1.391 + 1.392 +CLzmaDecoder::CLzmaDecoder() 1.393 +{ 1.394 + DecoderSpec = new NCompress::NLzma::CDecoder; 1.395 + Decoder = DecoderSpec; 1.396 +} 1.397 + 1.398 +HRESULT CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, 1.399 + const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) 1.400 +{ 1.401 + Byte buf[9]; 1.402 + RINOK(ReadStream_FALSE(inStream, buf, 9)); 1.403 + if (buf[2] != 5 || buf[3] != 0) 1.404 + return E_NOTIMPL; 1.405 + RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, 5)); 1.406 + return Decoder->Code(inStream, outStream, NULL, outSize, progress); 1.407 +} 1.408 + 1.409 +struct CMethodItem 1.410 +{ 1.411 + UInt16 ZipMethod; 1.412 + CMyComPtr<ICompressCoder> Coder; 1.413 +}; 1.414 + 1.415 +class CZipDecoder 1.416 +{ 1.417 + NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec; 1.418 + NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec; 1.419 + NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec; 1.420 + 1.421 + CMyComPtr<ICompressFilter> _zipCryptoDecoder; 1.422 + CMyComPtr<ICompressFilter> _pkAesDecoder; 1.423 + CMyComPtr<ICompressFilter> _wzAesDecoder; 1.424 + 1.425 + CFilterCoder *filterStreamSpec; 1.426 + CMyComPtr<ISequentialInStream> filterStream; 1.427 + CMyComPtr<ICryptoGetTextPassword> getTextPassword; 1.428 + CObjectVector<CMethodItem> methodItems; 1.429 + 1.430 +public: 1.431 + CZipDecoder(): 1.432 + _zipCryptoDecoderSpec(0), 1.433 + _pkAesDecoderSpec(0), 1.434 + _wzAesDecoderSpec(0), 1.435 + filterStreamSpec(0) {} 1.436 + 1.437 + HRESULT Decode( 1.438 + DECL_EXTERNAL_CODECS_LOC_VARS 1.439 + CInArchive &archive, const CItemEx &item, 1.440 + ISequentialOutStream *realOutStream, 1.441 + IArchiveExtractCallback *extractCallback, 1.442 + ICompressProgressInfo *compressProgress, 1.443 + UInt32 numThreads, Int32 &res); 1.444 +}; 1.445 + 1.446 +HRESULT CZipDecoder::Decode( 1.447 + DECL_EXTERNAL_CODECS_LOC_VARS 1.448 + CInArchive &archive, const CItemEx &item, 1.449 + ISequentialOutStream *realOutStream, 1.450 + IArchiveExtractCallback *extractCallback, 1.451 + ICompressProgressInfo *compressProgress, 1.452 + UInt32 numThreads, Int32 &res) 1.453 +{ 1.454 + res = NArchive::NExtract::NOperationResult::kDataError; 1.455 + CInStreamReleaser inStreamReleaser; 1.456 + 1.457 + bool needCRC = true; 1.458 + bool wzAesMode = false; 1.459 + bool pkAesMode = false; 1.460 + UInt16 methodId = item.CompressionMethod; 1.461 + if (item.IsEncrypted()) 1.462 + { 1.463 + if (item.IsStrongEncrypted()) 1.464 + { 1.465 + CStrongCryptoField f; 1.466 + if (item.CentralExtra.GetStrongCryptoField(f)) 1.467 + { 1.468 + pkAesMode = true; 1.469 + } 1.470 + if (!pkAesMode) 1.471 + { 1.472 + res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; 1.473 + return S_OK; 1.474 + } 1.475 + } 1.476 + if (methodId == NFileHeader::NCompressionMethod::kWzAES) 1.477 + { 1.478 + CWzAesExtraField aesField; 1.479 + if (item.CentralExtra.GetWzAesField(aesField)) 1.480 + { 1.481 + wzAesMode = true; 1.482 + needCRC = aesField.NeedCrc(); 1.483 + } 1.484 + } 1.485 + } 1.486 + 1.487 + COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC; 1.488 + CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; 1.489 + outStreamSpec->SetStream(realOutStream); 1.490 + outStreamSpec->Init(needCRC); 1.491 + 1.492 + UInt64 authenticationPos; 1.493 + 1.494 + CMyComPtr<ISequentialInStream> inStream; 1.495 + { 1.496 + UInt64 packSize = item.PackSize; 1.497 + if (wzAesMode) 1.498 + { 1.499 + if (packSize < NCrypto::NWzAes::kMacSize) 1.500 + return S_OK; 1.501 + packSize -= NCrypto::NWzAes::kMacSize; 1.502 + } 1.503 + UInt64 dataPos = item.GetDataPosition(); 1.504 + inStream.Attach(archive.CreateLimitedStream(dataPos, packSize)); 1.505 + authenticationPos = dataPos + packSize; 1.506 + } 1.507 + 1.508 + CMyComPtr<ICompressFilter> cryptoFilter; 1.509 + if (item.IsEncrypted()) 1.510 + { 1.511 + if (wzAesMode) 1.512 + { 1.513 + CWzAesExtraField aesField; 1.514 + if (!item.CentralExtra.GetWzAesField(aesField)) 1.515 + return S_OK; 1.516 + methodId = aesField.Method; 1.517 + if (!_wzAesDecoder) 1.518 + { 1.519 + _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder; 1.520 + _wzAesDecoder = _wzAesDecoderSpec; 1.521 + } 1.522 + cryptoFilter = _wzAesDecoder; 1.523 + Byte properties = aesField.Strength; 1.524 + RINOK(_wzAesDecoderSpec->SetDecoderProperties2(&properties, 1)); 1.525 + } 1.526 + else if (pkAesMode) 1.527 + { 1.528 + if (!_pkAesDecoder) 1.529 + { 1.530 + _pkAesDecoderSpec = new NCrypto::NZipStrong::CDecoder; 1.531 + _pkAesDecoder = _pkAesDecoderSpec; 1.532 + } 1.533 + cryptoFilter = _pkAesDecoder; 1.534 + } 1.535 + else 1.536 + { 1.537 + if (!_zipCryptoDecoder) 1.538 + { 1.539 + _zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder; 1.540 + _zipCryptoDecoder = _zipCryptoDecoderSpec; 1.541 + } 1.542 + cryptoFilter = _zipCryptoDecoder; 1.543 + } 1.544 + CMyComPtr<ICryptoSetPassword> cryptoSetPassword; 1.545 + RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword)); 1.546 + 1.547 + if (!getTextPassword) 1.548 + extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword); 1.549 + 1.550 + if (getTextPassword) 1.551 + { 1.552 + CMyComBSTR password; 1.553 + RINOK(getTextPassword->CryptoGetTextPassword(&password)); 1.554 + AString charPassword; 1.555 + if (wzAesMode || pkAesMode) 1.556 + { 1.557 + charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_ACP); 1.558 + /* 1.559 + for (int i = 0;; i++) 1.560 + { 1.561 + wchar_t c = password[i]; 1.562 + if (c == 0) 1.563 + break; 1.564 + if (c >= 0x80) 1.565 + { 1.566 + res = NArchive::NExtract::NOperationResult::kDataError; 1.567 + return S_OK; 1.568 + } 1.569 + charPassword += (char)c; 1.570 + } 1.571 + */ 1.572 + } 1.573 + else 1.574 + { 1.575 + // we use OEM. WinZip/Windows probably use ANSI for some files 1.576 + charPassword = UnicodeStringToMultiByte((const wchar_t *)password, CP_OEMCP); 1.577 + } 1.578 + HRESULT result = cryptoSetPassword->CryptoSetPassword( 1.579 + (const Byte *)(const char *)charPassword, charPassword.Length()); 1.580 + if (result != S_OK) 1.581 + return S_OK; 1.582 + } 1.583 + else 1.584 + { 1.585 + RINOK(cryptoSetPassword->CryptoSetPassword(0, 0)); 1.586 + } 1.587 + } 1.588 + 1.589 + int m; 1.590 + for (m = 0; m < methodItems.Size(); m++) 1.591 + if (methodItems[m].ZipMethod == methodId) 1.592 + break; 1.593 + 1.594 + if (m == methodItems.Size()) 1.595 + { 1.596 + CMethodItem mi; 1.597 + mi.ZipMethod = methodId; 1.598 + if (methodId == NFileHeader::NCompressionMethod::kStored) 1.599 + mi.Coder = new NCompress::CCopyCoder; 1.600 + else if (methodId == NFileHeader::NCompressionMethod::kShrunk) 1.601 + mi.Coder = new NCompress::NShrink::CDecoder; 1.602 + else if (methodId == NFileHeader::NCompressionMethod::kImploded) 1.603 + mi.Coder = new NCompress::NImplode::NDecoder::CCoder; 1.604 + else if (methodId == NFileHeader::NCompressionMethod::kLZMA) 1.605 + mi.Coder = new CLzmaDecoder; 1.606 + else 1.607 + { 1.608 + CMethodId szMethodID; 1.609 + if (methodId == NFileHeader::NCompressionMethod::kBZip2) 1.610 + szMethodID = kMethodId_BZip2; 1.611 + else 1.612 + { 1.613 + if (methodId > 0xFF) 1.614 + { 1.615 + res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; 1.616 + return S_OK; 1.617 + } 1.618 + szMethodID = kMethodId_ZipBase + (Byte)methodId; 1.619 + } 1.620 + 1.621 + RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS szMethodID, mi.Coder, false)); 1.622 + 1.623 + if (mi.Coder == 0) 1.624 + { 1.625 + res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; 1.626 + return S_OK; 1.627 + } 1.628 + } 1.629 + m = methodItems.Add(mi); 1.630 + } 1.631 + ICompressCoder *coder = methodItems[m].Coder; 1.632 + 1.633 + { 1.634 + CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; 1.635 + coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties); 1.636 + if (setDecoderProperties) 1.637 + { 1.638 + Byte properties = (Byte)item.Flags; 1.639 + RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1)); 1.640 + } 1.641 + } 1.642 + 1.643 + #ifdef COMPRESS_MT 1.644 + { 1.645 + CMyComPtr<ICompressSetCoderMt> setCoderMt; 1.646 + coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); 1.647 + if (setCoderMt) 1.648 + { 1.649 + RINOK(setCoderMt->SetNumberOfThreads(numThreads)); 1.650 + } 1.651 + } 1.652 + #endif 1.653 + 1.654 + { 1.655 + HRESULT result = S_OK; 1.656 + CMyComPtr<ISequentialInStream> inStreamNew; 1.657 + if (item.IsEncrypted()) 1.658 + { 1.659 + if (!filterStream) 1.660 + { 1.661 + filterStreamSpec = new CFilterCoder; 1.662 + filterStream = filterStreamSpec; 1.663 + } 1.664 + filterStreamSpec->Filter = cryptoFilter; 1.665 + if (wzAesMode) 1.666 + { 1.667 + result = _wzAesDecoderSpec->ReadHeader(inStream); 1.668 + } 1.669 + else if (pkAesMode) 1.670 + { 1.671 + result =_pkAesDecoderSpec->ReadHeader(inStream, item.FileCRC, item.UnPackSize); 1.672 + if (result == S_OK) 1.673 + { 1.674 + bool passwOK; 1.675 + result = _pkAesDecoderSpec->CheckPassword(passwOK); 1.676 + if (result == S_OK && !passwOK) 1.677 + result = S_FALSE; 1.678 + } 1.679 + } 1.680 + else 1.681 + { 1.682 + result = _zipCryptoDecoderSpec->ReadHeader(inStream); 1.683 + } 1.684 + 1.685 + if (result == S_OK) 1.686 + { 1.687 + RINOK(filterStreamSpec->SetInStream(inStream)); 1.688 + inStreamReleaser.FilterCoder = filterStreamSpec; 1.689 + inStreamNew = filterStream; 1.690 + if (wzAesMode) 1.691 + { 1.692 + if (!_wzAesDecoderSpec->CheckPasswordVerifyCode()) 1.693 + result = S_FALSE; 1.694 + } 1.695 + } 1.696 + } 1.697 + else 1.698 + inStreamNew = inStream; 1.699 + if (result == S_OK) 1.700 + result = coder->Code(inStreamNew, outStream, NULL, &item.UnPackSize, compressProgress); 1.701 + if (result == S_FALSE) 1.702 + return S_OK; 1.703 + if (result == E_NOTIMPL) 1.704 + { 1.705 + res = NArchive::NExtract::NOperationResult::kUnSupportedMethod; 1.706 + return S_OK; 1.707 + } 1.708 + 1.709 + RINOK(result); 1.710 + } 1.711 + bool crcOK = true; 1.712 + bool authOk = true; 1.713 + if (needCRC) 1.714 + crcOK = (outStreamSpec->GetCRC() == item.FileCRC); 1.715 + if (wzAesMode) 1.716 + { 1.717 + inStream.Attach(archive.CreateLimitedStream(authenticationPos, NCrypto::NWzAes::kMacSize)); 1.718 + if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK) 1.719 + authOk = false; 1.720 + } 1.721 + 1.722 + res = ((crcOK && authOk) ? 1.723 + NArchive::NExtract::NOperationResult::kOK : 1.724 + NArchive::NExtract::NOperationResult::kCRCError); 1.725 + return S_OK; 1.726 +} 1.727 + 1.728 + 1.729 +STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, 1.730 + Int32 _aTestMode, IArchiveExtractCallback *extractCallback) 1.731 +{ 1.732 + COM_TRY_BEGIN 1.733 + CZipDecoder myDecoder; 1.734 + bool testMode = (_aTestMode != 0); 1.735 + UInt64 totalUnPacked = 0, totalPacked = 0; 1.736 + bool allFilesMode = (numItems == UInt32(-1)); 1.737 + if (allFilesMode) 1.738 + numItems = m_Items.Size(); 1.739 + if(numItems == 0) 1.740 + return S_OK; 1.741 + UInt32 i; 1.742 + for(i = 0; i < numItems; i++) 1.743 + { 1.744 + const CItemEx &item = m_Items[allFilesMode ? i : indices[i]]; 1.745 + totalUnPacked += item.UnPackSize; 1.746 + totalPacked += item.PackSize; 1.747 + } 1.748 + RINOK(extractCallback->SetTotal(totalUnPacked)); 1.749 + 1.750 + UInt64 currentTotalUnPacked = 0, currentTotalPacked = 0; 1.751 + UInt64 currentItemUnPacked, currentItemPacked; 1.752 + 1.753 + CLocalProgress *lps = new CLocalProgress; 1.754 + CMyComPtr<ICompressProgressInfo> progress = lps; 1.755 + lps->Init(extractCallback, false); 1.756 + 1.757 + for (i = 0; i < numItems; i++, currentTotalUnPacked += currentItemUnPacked, 1.758 + currentTotalPacked += currentItemPacked) 1.759 + { 1.760 + currentItemUnPacked = 0; 1.761 + currentItemPacked = 0; 1.762 + 1.763 + lps->InSize = currentTotalPacked; 1.764 + lps->OutSize = currentTotalUnPacked; 1.765 + RINOK(lps->SetCur()); 1.766 + 1.767 + CMyComPtr<ISequentialOutStream> realOutStream; 1.768 + Int32 askMode = testMode ? 1.769 + NArchive::NExtract::NAskMode::kTest : 1.770 + NArchive::NExtract::NAskMode::kExtract; 1.771 + Int32 index = allFilesMode ? i : indices[i]; 1.772 + 1.773 + RINOK(extractCallback->GetStream(index, &realOutStream, askMode)); 1.774 + 1.775 + CItemEx item = m_Items[index]; 1.776 + if (!item.FromLocal) 1.777 + { 1.778 + HRESULT res = m_Archive.ReadLocalItemAfterCdItem(item); 1.779 + if (res == S_FALSE) 1.780 + { 1.781 + if (item.IsDir() || realOutStream || testMode) 1.782 + { 1.783 + RINOK(extractCallback->PrepareOperation(askMode)); 1.784 + realOutStream.Release(); 1.785 + RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod)); 1.786 + } 1.787 + continue; 1.788 + } 1.789 + RINOK(res); 1.790 + } 1.791 + 1.792 + if (item.IsDir() || item.IgnoreItem()) 1.793 + { 1.794 + // if (!testMode) 1.795 + { 1.796 + RINOK(extractCallback->PrepareOperation(askMode)); 1.797 + realOutStream.Release(); 1.798 + RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK)); 1.799 + } 1.800 + continue; 1.801 + } 1.802 + 1.803 + currentItemUnPacked = item.UnPackSize; 1.804 + currentItemPacked = item.PackSize; 1.805 + 1.806 + if (!testMode && (!realOutStream)) 1.807 + continue; 1.808 + 1.809 + RINOK(extractCallback->PrepareOperation(askMode)); 1.810 + 1.811 +#ifndef COMPRESS_MT 1.812 +#define _numThreads 1 1.813 +#endif 1.814 + 1.815 + Int32 res; 1.816 + RINOK(myDecoder.Decode( 1.817 + EXTERNAL_CODECS_VARS 1.818 + m_Archive, item, realOutStream, extractCallback, 1.819 + progress, 1.820 + _numThreads, 1.821 + res)); 1.822 + realOutStream.Release(); 1.823 + 1.824 + RINOK(extractCallback->SetOperationResult(res)) 1.825 + } 1.826 + return S_OK; 1.827 + COM_TRY_END 1.828 +} 1.829 + 1.830 +#ifndef EXTRACT_ONLY 1.831 +IMPL_ISetCompressCodecsInfo 1.832 +#endif 1.833 + 1.834 +}}