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 +}}