diff src/win32/7zip/7z/CPP/7zip/Archive/Rar/RarHandler.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/Rar/RarHandler.cpp	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,835 @@
     1.4 +// RarHandler.cpp
     1.5 +
     1.6 +#include "StdAfx.h"
     1.7 +
     1.8 +#include "Common/ComTry.h"
     1.9 +#include "Common/IntToString.h"
    1.10 +#include "Common/StringConvert.h"
    1.11 +
    1.12 +#include "Windows/PropVariant.h"
    1.13 +#include "Windows/Time.h"
    1.14 +
    1.15 +#include "../../IPassword.h"
    1.16 +
    1.17 +#include "../../Common/CreateCoder.h"
    1.18 +#include "../../Common/FilterCoder.h"
    1.19 +#include "../../Common/MethodId.h"
    1.20 +#include "../../Common/ProgressUtils.h"
    1.21 +
    1.22 +#include "../../Compress/CopyCoder.h"
    1.23 +
    1.24 +#include "../../Crypto/Rar20Crypto.h"
    1.25 +#include "../../Crypto/RarAes.h"
    1.26 +
    1.27 +#include "../Common/ItemNameUtils.h"
    1.28 +#include "../Common/OutStreamWithCRC.h"
    1.29 +
    1.30 +#include "RarHandler.h"
    1.31 +
    1.32 +using namespace NWindows;
    1.33 +using namespace NTime;
    1.34 +
    1.35 +namespace NArchive {
    1.36 +namespace NRar {
    1.37 +
    1.38 +static const wchar_t *kHostOS[] =
    1.39 +{
    1.40 +  L"MS DOS",
    1.41 +  L"OS/2",
    1.42 +  L"Win32",
    1.43 +  L"Unix",
    1.44 +  L"Mac OS",
    1.45 +  L"BeOS"
    1.46 +};
    1.47 +
    1.48 +static const int kNumHostOSes = sizeof(kHostOS) / sizeof(kHostOS[0]);
    1.49 +
    1.50 +static const wchar_t *kUnknownOS = L"Unknown";
    1.51 +
    1.52 +STATPROPSTG kProps[] =
    1.53 +{
    1.54 +  { NULL, kpidPath, VT_BSTR},
    1.55 +  { NULL, kpidIsDir, VT_BOOL},
    1.56 +  { NULL, kpidSize, VT_UI8},
    1.57 +  { NULL, kpidPackSize, VT_UI8},
    1.58 +  { NULL, kpidMTime, VT_FILETIME},
    1.59 +  { NULL, kpidCTime, VT_FILETIME},
    1.60 +  { NULL, kpidATime, VT_FILETIME},
    1.61 +  { NULL, kpidAttrib, VT_UI4},
    1.62 +
    1.63 +  { NULL, kpidEncrypted, VT_BOOL},
    1.64 +  { NULL, kpidSolid, VT_BOOL},
    1.65 +  { NULL, kpidCommented, VT_BOOL},
    1.66 +  { NULL, kpidSplitBefore, VT_BOOL},
    1.67 +  { NULL, kpidSplitAfter, VT_BOOL},
    1.68 +  { NULL, kpidCRC, VT_UI4},
    1.69 +  { NULL, kpidHostOS, VT_BSTR},
    1.70 +  { NULL, kpidMethod, VT_BSTR},
    1.71 +  { NULL, kpidUnpackVer, VT_UI1}
    1.72 +};
    1.73 +
    1.74 +STATPROPSTG kArcProps[] =
    1.75 +{
    1.76 +  { NULL, kpidSolid, VT_BOOL},
    1.77 +  { NULL, kpidNumBlocks, VT_UI4},
    1.78 +  // { NULL, kpidEncrypted, VT_BOOL},
    1.79 +  { NULL, kpidIsVolume, VT_BOOL},
    1.80 +  { NULL, kpidNumVolumes, VT_UI4},
    1.81 +  { NULL, kpidPhySize, VT_UI8}
    1.82 +  // { NULL, kpidCommented, VT_BOOL}
    1.83 +};
    1.84 +
    1.85 +IMP_IInArchive_Props
    1.86 +IMP_IInArchive_ArcProps
    1.87 +
    1.88 +UInt64 CHandler::GetPackSize(int refIndex) const
    1.89 +{
    1.90 +  const CRefItem &refItem = _refItems[refIndex];
    1.91 +  UInt64 totalPackSize = 0;
    1.92 +  for (int i = 0; i < refItem.NumItems; i++)
    1.93 +    totalPackSize += _items[refItem.ItemIndex + i].PackSize;
    1.94 +  return totalPackSize;
    1.95 +}
    1.96 +
    1.97 +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
    1.98 +{
    1.99 +  // COM_TRY_BEGIN
   1.100 +  NWindows::NCOM::CPropVariant prop;
   1.101 +  switch(propID)
   1.102 +  {
   1.103 +    case kpidSolid: prop = _archiveInfo.IsSolid(); break;
   1.104 +    // case kpidEncrypted: prop = _archiveInfo.IsEncrypted(); break; // it's for encrypted names.
   1.105 +    case kpidIsVolume: prop = _archiveInfo.IsVolume(); break;
   1.106 +    case kpidNumVolumes: prop = (UInt32)_archives.Size(); break;
   1.107 +    case kpidOffset: if (_archiveInfo.StartPosition != 0) prop = _archiveInfo.StartPosition; break;
   1.108 +    // case kpidCommented: prop = _archiveInfo.IsCommented(); break;
   1.109 +    case kpidNumBlocks:
   1.110 +    {
   1.111 +      UInt32 numBlocks = 0;
   1.112 +      for (int i = 0; i < _refItems.Size(); i++)
   1.113 +        if (!IsSolid(i))
   1.114 +          numBlocks++;
   1.115 +      prop = (UInt32)numBlocks;
   1.116 +      break;
   1.117 +    }
   1.118 +  }
   1.119 +  prop.Detach(value);
   1.120 +  return S_OK;
   1.121 +  // COM_TRY_END
   1.122 +}
   1.123 +
   1.124 +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
   1.125 +{
   1.126 +  *numItems = _refItems.Size();
   1.127 +  return S_OK;
   1.128 +}
   1.129 +
   1.130 +static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &result)
   1.131 +{
   1.132 +  if (!DosTimeToFileTime(rarTime.DosTime, result))
   1.133 +    return false;
   1.134 +  UInt64 value =  (((UInt64)result.dwHighDateTime) << 32) + result.dwLowDateTime;
   1.135 +  value += (UInt64)rarTime.LowSecond * 10000000;
   1.136 +  value += ((UInt64)rarTime.SubTime[2] << 16) +
   1.137 +    ((UInt64)rarTime.SubTime[1] << 8) +
   1.138 +    ((UInt64)rarTime.SubTime[0]);
   1.139 +  result.dwLowDateTime = (DWORD)value;
   1.140 +  result.dwHighDateTime = DWORD(value >> 32);
   1.141 +  return true;
   1.142 +}
   1.143 +
   1.144 +static void RarTimeToProp(const CRarTime &rarTime, NWindows::NCOM::CPropVariant &prop)
   1.145 +{
   1.146 +  FILETIME localFileTime, utcFileTime;
   1.147 +  if (RarTimeToFileTime(rarTime, localFileTime))
   1.148 +  {
   1.149 +    if (!LocalFileTimeToFileTime(&localFileTime, &utcFileTime))
   1.150 +      utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
   1.151 +  }
   1.152 +  else
   1.153 +    utcFileTime.dwHighDateTime = utcFileTime.dwLowDateTime = 0;
   1.154 +  prop = utcFileTime;
   1.155 +}
   1.156 +
   1.157 +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID,  PROPVARIANT *value)
   1.158 +{
   1.159 +  COM_TRY_BEGIN
   1.160 +  NWindows::NCOM::CPropVariant prop;
   1.161 +  const CRefItem &refItem = _refItems[index];
   1.162 +  const CItemEx &item = _items[refItem.ItemIndex];
   1.163 +  switch(propID)
   1.164 +  {
   1.165 +    case kpidPath:
   1.166 +    {
   1.167 +      UString u;
   1.168 +      if (item.HasUnicodeName() && !item.UnicodeName.IsEmpty())
   1.169 +        u = item.UnicodeName;
   1.170 +      else
   1.171 +        u = MultiByteToUnicodeString(item.Name, CP_OEMCP);
   1.172 +      prop = (const wchar_t *)NItemName::WinNameToOSName(u);
   1.173 +      break;
   1.174 +    }
   1.175 +    case kpidIsDir: prop = item.IsDir(); break;
   1.176 +    case kpidSize: prop = item.Size; break;
   1.177 +    case kpidPackSize: prop = GetPackSize(index); break;
   1.178 +    case kpidMTime: RarTimeToProp(item.MTime, prop); break;
   1.179 +    case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break;
   1.180 +    case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break;
   1.181 +    case kpidAttrib: prop = item.GetWinAttributes(); break;
   1.182 +    case kpidEncrypted: prop = item.IsEncrypted(); break;
   1.183 +    case kpidSolid: prop = IsSolid(index); break;
   1.184 +    case kpidCommented: prop = item.IsCommented(); break;
   1.185 +    case kpidSplitBefore: prop = item.IsSplitBefore(); break;
   1.186 +    case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break;
   1.187 +    case kpidCRC:
   1.188 +    {
   1.189 +      const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
   1.190 +      prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC);
   1.191 +      break;
   1.192 +    }
   1.193 +    case kpidUnpackVer: prop = item.UnPackVersion; break;
   1.194 +    case kpidMethod:
   1.195 +    {
   1.196 +      UString method;
   1.197 +      if (item.Method >= Byte('0') && item.Method <= Byte('5'))
   1.198 +      {
   1.199 +        method = L"m";
   1.200 +        wchar_t temp[32];
   1.201 +        ConvertUInt64ToString(item.Method - Byte('0'), temp);
   1.202 +        method += temp;
   1.203 +        if (!item.IsDir())
   1.204 +        {
   1.205 +          method += L":";
   1.206 +          ConvertUInt64ToString(16 + item.GetDictSize(), temp);
   1.207 +          method += temp;
   1.208 +        }
   1.209 +      }
   1.210 +      else
   1.211 +      {
   1.212 +        wchar_t temp[32];
   1.213 +        ConvertUInt64ToString(item.Method, temp);
   1.214 +        method += temp;
   1.215 +      }
   1.216 +      prop = method;
   1.217 +      break;
   1.218 +    }
   1.219 +    case kpidHostOS: prop = (item.HostOS < kNumHostOSes) ? (kHostOS[item.HostOS]) : kUnknownOS; break;
   1.220 +  }
   1.221 +  prop.Detach(value);
   1.222 +  return S_OK;
   1.223 +  COM_TRY_END
   1.224 +}
   1.225 +
   1.226 +class CVolumeName
   1.227 +{
   1.228 +  bool _first;
   1.229 +  bool _newStyle;
   1.230 +  UString _unchangedPart;
   1.231 +  UString _changedPart;
   1.232 +  UString _afterPart;
   1.233 +public:
   1.234 +  CVolumeName(): _newStyle(true) {};
   1.235 +
   1.236 +  bool InitName(const UString &name, bool newStyle)
   1.237 +  {
   1.238 +    _first = true;
   1.239 +    _newStyle = newStyle;
   1.240 +    int dotPos = name.ReverseFind('.');
   1.241 +    UString basePart = name;
   1.242 +    if (dotPos >= 0)
   1.243 +    {
   1.244 +      UString ext = name.Mid(dotPos + 1);
   1.245 +      if (ext.CompareNoCase(L"rar") == 0)
   1.246 +      {
   1.247 +        _afterPart = name.Mid(dotPos);
   1.248 +        basePart = name.Left(dotPos);
   1.249 +      }
   1.250 +      else if (ext.CompareNoCase(L"exe") == 0)
   1.251 +      {
   1.252 +        _afterPart = L".rar";
   1.253 +        basePart = name.Left(dotPos);
   1.254 +      }
   1.255 +      else if (!_newStyle)
   1.256 +      {
   1.257 +        if (ext.CompareNoCase(L"000") == 0 || ext.CompareNoCase(L"001") == 0)
   1.258 +        {
   1.259 +          _afterPart.Empty();
   1.260 +          _first = false;
   1.261 +          _changedPart = ext;
   1.262 +          _unchangedPart = name.Left(dotPos + 1);
   1.263 +          return true;
   1.264 +        }
   1.265 +      }
   1.266 +    }
   1.267 +
   1.268 +    if (!_newStyle)
   1.269 +    {
   1.270 +      _afterPart.Empty();
   1.271 +      _unchangedPart = basePart + UString(L".");
   1.272 +      _changedPart = L"r00";
   1.273 +      return true;
   1.274 +    }
   1.275 +
   1.276 +    int numLetters = 1;
   1.277 +    if (basePart.Right(numLetters) == L"1" || basePart.Right(numLetters) == L"0")
   1.278 +    {
   1.279 +      while (numLetters < basePart.Length())
   1.280 +      {
   1.281 +        if (basePart[basePart.Length() - numLetters - 1] != '0')
   1.282 +          break;
   1.283 +        numLetters++;
   1.284 +      }
   1.285 +    }
   1.286 +    else
   1.287 +      return false;
   1.288 +    _unchangedPart = basePart.Left(basePart.Length() - numLetters);
   1.289 +    _changedPart = basePart.Right(numLetters);
   1.290 +    return true;
   1.291 +  }
   1.292 +
   1.293 +  UString GetNextName()
   1.294 +  {
   1.295 +    UString newName;
   1.296 +    if (_newStyle || !_first)
   1.297 +    {
   1.298 +      int i;
   1.299 +      int numLetters = _changedPart.Length();
   1.300 +      for (i = numLetters - 1; i >= 0; i--)
   1.301 +      {
   1.302 +        wchar_t c = _changedPart[i];
   1.303 +        if (c == L'9')
   1.304 +        {
   1.305 +          c = L'0';
   1.306 +          newName = c + newName;
   1.307 +          if (i == 0)
   1.308 +            newName = UString(L'1') + newName;
   1.309 +          continue;
   1.310 +        }
   1.311 +        c++;
   1.312 +        newName = UString(c) + newName;
   1.313 +        i--;
   1.314 +        for (; i >= 0; i--)
   1.315 +          newName = _changedPart[i] + newName;
   1.316 +        break;
   1.317 +      }
   1.318 +      _changedPart = newName;
   1.319 +    }
   1.320 +    _first = false;
   1.321 +    return _unchangedPart + _changedPart + _afterPart;
   1.322 +  }
   1.323 +};
   1.324 +
   1.325 +HRESULT CHandler::Open2(IInStream *stream,
   1.326 +    const UInt64 *maxCheckStartPosition,
   1.327 +    IArchiveOpenCallback *openArchiveCallback)
   1.328 +{
   1.329 +  {
   1.330 +    CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
   1.331 +    CMyComPtr<ICryptoGetTextPassword> getTextPassword;
   1.332 +    CMyComPtr<IArchiveOpenCallback> openArchiveCallbackWrap = openArchiveCallback;
   1.333 +    
   1.334 +    CVolumeName seqName;
   1.335 +
   1.336 +    UInt64 totalBytes = 0;
   1.337 +    UInt64 curBytes = 0;
   1.338 +
   1.339 +    if (openArchiveCallback != NULL)
   1.340 +    {
   1.341 +      openArchiveCallbackWrap.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback);
   1.342 +      openArchiveCallbackWrap.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
   1.343 +    }
   1.344 +
   1.345 +    for (;;)
   1.346 +    {
   1.347 +      CMyComPtr<IInStream> inStream;
   1.348 +      if (!_archives.IsEmpty())
   1.349 +      {
   1.350 +        if (!openVolumeCallback)
   1.351 +          break;
   1.352 +        
   1.353 +        if(_archives.Size() == 1)
   1.354 +        {
   1.355 +          if (!_archiveInfo.IsVolume())
   1.356 +            break;
   1.357 +          UString baseName;
   1.358 +          {
   1.359 +            NCOM::CPropVariant prop;
   1.360 +            RINOK(openVolumeCallback->GetProperty(kpidName, &prop));
   1.361 +            if (prop.vt != VT_BSTR)
   1.362 +              break;
   1.363 +            baseName = prop.bstrVal;
   1.364 +          }
   1.365 +          seqName.InitName(baseName, _archiveInfo.HaveNewVolumeName());
   1.366 +        }
   1.367 +
   1.368 +        UString fullName = seqName.GetNextName();
   1.369 +        HRESULT result = openVolumeCallback->GetStream(fullName, &inStream);
   1.370 +        if (result == S_FALSE)
   1.371 +          break;
   1.372 +        if (result != S_OK)
   1.373 +          return result;
   1.374 +        if (!stream)
   1.375 +          break;
   1.376 +      }
   1.377 +      else
   1.378 +        inStream = stream;
   1.379 +
   1.380 +      UInt64 endPos = 0;
   1.381 +      if (openArchiveCallback != NULL)
   1.382 +      {
   1.383 +        RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
   1.384 +        RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
   1.385 +        totalBytes += endPos;
   1.386 +        RINOK(openArchiveCallback->SetTotal(NULL, &totalBytes));
   1.387 +      }
   1.388 +      
   1.389 +      NArchive::NRar::CInArchive archive;
   1.390 +      RINOK(archive.Open(inStream, maxCheckStartPosition));
   1.391 +
   1.392 +      if (_archives.IsEmpty())
   1.393 +        archive.GetArchiveInfo(_archiveInfo);
   1.394 +     
   1.395 +      CItemEx item;
   1.396 +      for (;;)
   1.397 +      {
   1.398 +        HRESULT result = archive.GetNextItem(item, getTextPassword);
   1.399 +        if (result == S_FALSE)
   1.400 +          break;
   1.401 +        RINOK(result);
   1.402 +        if (item.IgnoreItem())
   1.403 +          continue;
   1.404 +
   1.405 +        bool needAdd = true;
   1.406 +        if (item.IsSplitBefore())
   1.407 +        {
   1.408 +          if (!_refItems.IsEmpty())
   1.409 +          {
   1.410 +            CRefItem &refItem = _refItems.Back();
   1.411 +            refItem.NumItems++;
   1.412 +            needAdd = false;
   1.413 +          }
   1.414 +        }
   1.415 +        if (needAdd)
   1.416 +        {
   1.417 +          CRefItem refItem;
   1.418 +          refItem.ItemIndex = _items.Size();
   1.419 +          refItem.NumItems = 1;
   1.420 +          refItem.VolumeIndex = _archives.Size();
   1.421 +          _refItems.Add(refItem);
   1.422 +        }
   1.423 +        _items.Add(item);
   1.424 +        if (openArchiveCallback != NULL && _items.Size() % 100 == 0)
   1.425 +        {
   1.426 +          UInt64 numFiles = _items.Size();
   1.427 +          UInt64 numBytes = curBytes + item.Position;
   1.428 +          RINOK(openArchiveCallback->SetCompleted(&numFiles, &numBytes));
   1.429 +        }
   1.430 +      }
   1.431 +      curBytes += endPos;
   1.432 +      _archives.Add(archive);
   1.433 +    }
   1.434 +  }
   1.435 +  return S_OK;
   1.436 +}
   1.437 +
   1.438 +STDMETHODIMP CHandler::Open(IInStream *stream,
   1.439 +    const UInt64 *maxCheckStartPosition,
   1.440 +    IArchiveOpenCallback *openArchiveCallback)
   1.441 +{
   1.442 +  COM_TRY_BEGIN
   1.443 +  Close();
   1.444 +  try
   1.445 +  {
   1.446 +    HRESULT res = Open2(stream, maxCheckStartPosition, openArchiveCallback);
   1.447 +    if (res != S_OK)
   1.448 +      Close();
   1.449 +    return res;
   1.450 +  }
   1.451 +  catch(const CInArchiveException &) { Close(); return S_FALSE; }
   1.452 +  catch(...) { Close(); throw; }
   1.453 +  COM_TRY_END
   1.454 +}
   1.455 +
   1.456 +STDMETHODIMP CHandler::Close()
   1.457 +{
   1.458 +  COM_TRY_BEGIN
   1.459 +  _refItems.Clear();
   1.460 +  _items.Clear();
   1.461 +  _archives.Clear();
   1.462 +  return S_OK;
   1.463 +  COM_TRY_END
   1.464 +}
   1.465 +
   1.466 +struct CMethodItem
   1.467 +{
   1.468 +  Byte RarUnPackVersion;
   1.469 +  CMyComPtr<ICompressCoder> Coder;
   1.470 +};
   1.471 +
   1.472 +
   1.473 +STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
   1.474 +    Int32 _aTestMode, IArchiveExtractCallback *_anExtractCallback)
   1.475 +{
   1.476 +  COM_TRY_BEGIN
   1.477 +  CMyComPtr<ICryptoGetTextPassword> getTextPassword;
   1.478 +  bool testMode = (_aTestMode != 0);
   1.479 +  CMyComPtr<IArchiveExtractCallback> extractCallback = _anExtractCallback;
   1.480 +  UInt64 censoredTotalUnPacked = 0,
   1.481 +        // censoredTotalPacked = 0,
   1.482 +        importantTotalUnPacked = 0;
   1.483 +        // importantTotalPacked = 0;
   1.484 +  bool allFilesMode = (numItems == UInt32(-1));
   1.485 +  if (allFilesMode)
   1.486 +    numItems = _refItems.Size();
   1.487 +  if(numItems == 0)
   1.488 +    return S_OK;
   1.489 +  int lastIndex = 0;
   1.490 +  CRecordVector<int> importantIndexes;
   1.491 +  CRecordVector<bool> extractStatuses;
   1.492 +
   1.493 +  for(UInt32 t = 0; t < numItems; t++)
   1.494 +  {
   1.495 +    int index = allFilesMode ? t : indices[t];
   1.496 +    const CRefItem &refItem = _refItems[index];
   1.497 +    const CItemEx &item = _items[refItem.ItemIndex];
   1.498 +    censoredTotalUnPacked += item.Size;
   1.499 +    // censoredTotalPacked += item.PackSize;
   1.500 +    int j;
   1.501 +    for(j = lastIndex; j <= index; j++)
   1.502 +      // if(!_items[_refItems[j].ItemIndex].IsSolid())
   1.503 +      if(!IsSolid(j))
   1.504 +        lastIndex = j;
   1.505 +    for(j = lastIndex; j <= index; j++)
   1.506 +    {
   1.507 +      const CRefItem &refItem = _refItems[j];
   1.508 +      const CItemEx &item = _items[refItem.ItemIndex];
   1.509 +
   1.510 +      // const CItemEx &item = _items[j];
   1.511 +
   1.512 +      importantTotalUnPacked += item.Size;
   1.513 +      // importantTotalPacked += item.PackSize;
   1.514 +      importantIndexes.Add(j);
   1.515 +      extractStatuses.Add(j == index);
   1.516 +    }
   1.517 +    lastIndex = index + 1;
   1.518 +  }
   1.519 +
   1.520 +  extractCallback->SetTotal(importantTotalUnPacked);
   1.521 +  UInt64 currentImportantTotalUnPacked = 0;
   1.522 +  UInt64 currentImportantTotalPacked = 0;
   1.523 +  UInt64 currentUnPackSize, currentPackSize;
   1.524 +
   1.525 +  CObjectVector<CMethodItem> methodItems;
   1.526 +
   1.527 +  NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
   1.528 +  CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
   1.529 +
   1.530 +  CFilterCoder *filterStreamSpec = new CFilterCoder;
   1.531 +  CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
   1.532 +
   1.533 +  NCrypto::NRar20::CDecoder *rar20CryptoDecoderSpec = NULL;
   1.534 +  CMyComPtr<ICompressFilter> rar20CryptoDecoder;
   1.535 +  NCrypto::NRar29::CDecoder *rar29CryptoDecoderSpec = NULL;
   1.536 +  CMyComPtr<ICompressFilter> rar29CryptoDecoder;
   1.537 +
   1.538 +  CFolderInStream *folderInStreamSpec = NULL;
   1.539 +  CMyComPtr<ISequentialInStream> folderInStream;
   1.540 +
   1.541 +  CLocalProgress *lps = new CLocalProgress;
   1.542 +  CMyComPtr<ICompressProgressInfo> progress = lps;
   1.543 +  lps->Init(extractCallback, false);
   1.544 +
   1.545 +  bool solidStart = true;
   1.546 +  for(int i = 0; i < importantIndexes.Size(); i++,
   1.547 +      currentImportantTotalUnPacked += currentUnPackSize,
   1.548 +      currentImportantTotalPacked += currentPackSize)
   1.549 +  {
   1.550 +    lps->InSize = currentImportantTotalPacked;
   1.551 +    lps->OutSize = currentImportantTotalUnPacked;
   1.552 +    RINOK(lps->SetCur());
   1.553 +    CMyComPtr<ISequentialOutStream> realOutStream;
   1.554 +
   1.555 +    Int32 askMode;
   1.556 +    if(extractStatuses[i])
   1.557 +      askMode = testMode ?
   1.558 +          NArchive::NExtract::NAskMode::kTest :
   1.559 +          NArchive::NExtract::NAskMode::kExtract;
   1.560 +    else
   1.561 +      askMode = NArchive::NExtract::NAskMode::kSkip;
   1.562 +
   1.563 +    UInt32 index = importantIndexes[i];
   1.564 +
   1.565 +    const CRefItem &refItem = _refItems[index];
   1.566 +    const CItemEx &item = _items[refItem.ItemIndex];
   1.567 +
   1.568 +    currentUnPackSize = item.Size;
   1.569 +
   1.570 +    currentPackSize = GetPackSize(index);
   1.571 +
   1.572 +    if(item.IgnoreItem())
   1.573 +      continue;
   1.574 +
   1.575 +    RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
   1.576 +
   1.577 +    if (!IsSolid(index))
   1.578 +      solidStart = true;
   1.579 +    if(item.IsDir())
   1.580 +    {
   1.581 +      RINOK(extractCallback->PrepareOperation(askMode));
   1.582 +      RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
   1.583 +      continue;
   1.584 +    }
   1.585 +
   1.586 +    bool mustBeProcessedAnywhere = false;
   1.587 +    if(i < importantIndexes.Size() - 1)
   1.588 +    {
   1.589 +      // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]];
   1.590 +      // const CItemEx &nextItemInfo = _items[nextRefItem.ItemIndex];
   1.591 +      // mustBeProcessedAnywhere = nextItemInfo.IsSolid();
   1.592 +      mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]);
   1.593 +    }
   1.594 +    
   1.595 +    if (!mustBeProcessedAnywhere && !testMode && !realOutStream)
   1.596 +      continue;
   1.597 +    
   1.598 +    if (!realOutStream && !testMode)
   1.599 +      askMode = NArchive::NExtract::NAskMode::kSkip;
   1.600 +
   1.601 +    RINOK(extractCallback->PrepareOperation(askMode));
   1.602 +
   1.603 +    COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
   1.604 +    CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
   1.605 +    outStreamSpec->SetStream(realOutStream);
   1.606 +    outStreamSpec->Init();
   1.607 +    realOutStream.Release();
   1.608 +    
   1.609 +    /*
   1.610 +    for (int partIndex = 0; partIndex < 1; partIndex++)
   1.611 +    {
   1.612 +    CMyComPtr<ISequentialInStream> inStream;
   1.613 +
   1.614 +    // item redefinition
   1.615 +    const CItemEx &item = _items[refItem.ItemIndex + partIndex];
   1.616 +
   1.617 +    NArchive::NRar::CInArchive &archive = _archives[refItem.VolumeIndex + partIndex];
   1.618 +
   1.619 +    inStream.Attach(archive.CreateLimitedStream(item.GetDataPosition(),
   1.620 +      item.PackSize));
   1.621 +    */
   1.622 +    if (!folderInStream)
   1.623 +    {
   1.624 +      folderInStreamSpec = new CFolderInStream;
   1.625 +      folderInStream = folderInStreamSpec;
   1.626 +    }
   1.627 +
   1.628 +    folderInStreamSpec->Init(&_archives, &_items, refItem);
   1.629 +
   1.630 +    UInt64 packSize = currentPackSize;
   1.631 +
   1.632 +    // packedPos += item.PackSize;
   1.633 +    // unpackedPos += 0;
   1.634 +    
   1.635 +    CMyComPtr<ISequentialInStream> inStream;
   1.636 +    if (item.IsEncrypted())
   1.637 +    {
   1.638 +      CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
   1.639 +      if (item.UnPackVersion >= 29)
   1.640 +      {
   1.641 +        if (!rar29CryptoDecoder)
   1.642 +        {
   1.643 +          rar29CryptoDecoderSpec = new NCrypto::NRar29::CDecoder;
   1.644 +          rar29CryptoDecoder = rar29CryptoDecoderSpec;
   1.645 +          // RINOK(rar29CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar29Decoder));
   1.646 +        }
   1.647 +        rar29CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
   1.648 +        CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
   1.649 +        RINOK(rar29CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
   1.650 +            &cryptoProperties));
   1.651 +        RINOK(cryptoProperties->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0));
   1.652 +        filterStreamSpec->Filter = rar29CryptoDecoder;
   1.653 +      }
   1.654 +      else if (item.UnPackVersion >= 20)
   1.655 +      {
   1.656 +        if (!rar20CryptoDecoder)
   1.657 +        {
   1.658 +          rar20CryptoDecoderSpec = new NCrypto::NRar20::CDecoder;
   1.659 +          rar20CryptoDecoder = rar20CryptoDecoderSpec;
   1.660 +          // RINOK(rar20CryptoDecoder.CoCreateInstance(CLSID_CCryptoRar20Decoder));
   1.661 +        }
   1.662 +        filterStreamSpec->Filter = rar20CryptoDecoder;
   1.663 +      }
   1.664 +      else
   1.665 +      {
   1.666 +        outStream.Release();
   1.667 +        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
   1.668 +        continue;
   1.669 +      }
   1.670 +      RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword,
   1.671 +          &cryptoSetPassword));
   1.672 +
   1.673 +      if (!getTextPassword)
   1.674 +        extractCallback.QueryInterface(IID_ICryptoGetTextPassword,
   1.675 +          &getTextPassword);
   1.676 +      if (getTextPassword)
   1.677 +      {
   1.678 +        CMyComBSTR password;
   1.679 +        RINOK(getTextPassword->CryptoGetTextPassword(&password));
   1.680 +        if (item.UnPackVersion >= 29)
   1.681 +        {
   1.682 +          CByteBuffer buffer;
   1.683 +          UString unicodePassword(password);
   1.684 +          const UInt32 sizeInBytes = unicodePassword.Length() * 2;
   1.685 +          buffer.SetCapacity(sizeInBytes);
   1.686 +          for (int i = 0; i < unicodePassword.Length(); i++)
   1.687 +          {
   1.688 +            wchar_t c = unicodePassword[i];
   1.689 +            ((Byte *)buffer)[i * 2] = (Byte)c;
   1.690 +            ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
   1.691 +          }
   1.692 +          RINOK(cryptoSetPassword->CryptoSetPassword(
   1.693 +            (const Byte *)buffer, sizeInBytes));
   1.694 +        }
   1.695 +        else
   1.696 +        {
   1.697 +          AString oemPassword = UnicodeStringToMultiByte(
   1.698 +            (const wchar_t *)password, CP_OEMCP);
   1.699 +          RINOK(cryptoSetPassword->CryptoSetPassword(
   1.700 +            (const Byte *)(const char *)oemPassword, oemPassword.Length()));
   1.701 +        }
   1.702 +      }
   1.703 +      else
   1.704 +      {
   1.705 +        RINOK(cryptoSetPassword->CryptoSetPassword(0, 0));
   1.706 +      }
   1.707 +      filterStreamSpec->SetInStream(folderInStream);
   1.708 +      inStream = filterStream;
   1.709 +    }
   1.710 +    else
   1.711 +    {
   1.712 +      inStream = folderInStream;
   1.713 +    }
   1.714 +    CMyComPtr<ICompressCoder> commonCoder;
   1.715 +    switch(item.Method)
   1.716 +    {
   1.717 +      case '0':
   1.718 +      {
   1.719 +        commonCoder = copyCoder;
   1.720 +        break;
   1.721 +      }
   1.722 +      case '1':
   1.723 +      case '2':
   1.724 +      case '3':
   1.725 +      case '4':
   1.726 +      case '5':
   1.727 +      {
   1.728 +        /*
   1.729 +        if (item.UnPackVersion >= 29)
   1.730 +        {
   1.731 +          outStream.Release();
   1.732 +          RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
   1.733 +          continue;
   1.734 +        }
   1.735 +        */
   1.736 +        int m;
   1.737 +        for (m = 0; m < methodItems.Size(); m++)
   1.738 +          if (methodItems[m].RarUnPackVersion == item.UnPackVersion)
   1.739 +            break;
   1.740 +        if (m == methodItems.Size())
   1.741 +        {
   1.742 +          CMethodItem mi;
   1.743 +          mi.RarUnPackVersion = item.UnPackVersion;
   1.744 +
   1.745 +          mi.Coder.Release();
   1.746 +          if (item.UnPackVersion <= 30)
   1.747 +          {
   1.748 +            UInt32 methodID = 0x040300;
   1.749 +            if (item.UnPackVersion < 20)
   1.750 +              methodID += 1;
   1.751 +            else if (item.UnPackVersion < 29)
   1.752 +              methodID += 2;
   1.753 +            else
   1.754 +              methodID += 3;
   1.755 +            RINOK(CreateCoder(EXTERNAL_CODECS_VARS methodID, mi.Coder, false));
   1.756 +          }
   1.757 +         
   1.758 +          if (mi.Coder == 0)
   1.759 +          {
   1.760 +            outStream.Release();
   1.761 +            RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
   1.762 +            continue;
   1.763 +          }
   1.764 +
   1.765 +          m = methodItems.Add(mi);
   1.766 +        }
   1.767 +        CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder;
   1.768 +
   1.769 +        CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
   1.770 +        RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2,
   1.771 +            &compressSetDecoderProperties));
   1.772 +        
   1.773 +        Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
   1.774 +        if (solidStart)
   1.775 +        {
   1.776 +          isSolid = false;
   1.777 +          solidStart = false;
   1.778 +        }
   1.779 +
   1.780 +
   1.781 +        RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1));
   1.782 +          
   1.783 +        commonCoder = decoder;
   1.784 +        break;
   1.785 +      }
   1.786 +      default:
   1.787 +        outStream.Release();
   1.788 +        RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
   1.789 +        continue;
   1.790 +    }
   1.791 +    HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &item.Size, progress);
   1.792 +    if (item.IsEncrypted())
   1.793 +      filterStreamSpec->ReleaseInStream();
   1.794 +    if (result == S_FALSE)
   1.795 +    {
   1.796 +      outStream.Release();
   1.797 +      RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kDataError));
   1.798 +      continue;
   1.799 +    }
   1.800 +    if (result != S_OK)
   1.801 +      return result;
   1.802 +
   1.803 +    /*
   1.804 +    if (refItem.NumItems == 1 &&
   1.805 +        !item.IsSplitBefore() && !item.IsSplitAfter())
   1.806 +    */
   1.807 +    {
   1.808 +      const CItemEx &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
   1.809 +      bool crcOK = outStreamSpec->GetCRC() == lastItem.FileCRC;
   1.810 +      outStream.Release();
   1.811 +      RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK:
   1.812 +          NArchive::NExtract::NOperationResult::kCRCError));
   1.813 +    }
   1.814 +    /*
   1.815 +    else
   1.816 +    {
   1.817 +      bool crcOK = true;
   1.818 +      for (int partIndex = 0; partIndex < refItem.NumItems; partIndex++)
   1.819 +      {
   1.820 +        const CItemEx &item = _items[refItem.ItemIndex + partIndex];
   1.821 +        if (item.FileCRC != folderInStreamSpec->CRCs[partIndex])
   1.822 +        {
   1.823 +          crcOK = false;
   1.824 +          break;
   1.825 +        }
   1.826 +      }
   1.827 +      RINOK(extractCallback->SetOperationResult(crcOK ? NArchive::NExtract::NOperationResult::kOK:
   1.828 +          NArchive::NExtract::NOperationResult::kCRCError));
   1.829 +    }
   1.830 +    */
   1.831 +  }
   1.832 +  return S_OK;
   1.833 +  COM_TRY_END
   1.834 +}
   1.835 +
   1.836 +IMPL_ISetCompressCodecsInfo
   1.837 +
   1.838 +}}