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