tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ExtractCallback.cpp (26343B)


      1 // ExtractCallback.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 
      6 #include "../../../Common/ComTry.h"
      7 #include "../../../Common/IntToString.h"
      8 #include "../../../Common/Lang.h"
      9 #include "../../../Common/StringConvert.h"
     10 
     11 #include "../../../Windows/ErrorMsg.h"
     12 #include "../../../Windows/FileDir.h"
     13 #include "../../../Windows/FileFind.h"
     14 #include "../../../Windows/PropVariantConv.h"
     15 
     16 #include "../../Common/FilePathAutoRename.h"
     17 #include "../../Common/StreamUtils.h"
     18 #include "../Common/ExtractingFilePath.h"
     19 
     20 #ifndef _SFX
     21 #include "../Common/ZipRegistry.h"
     22 #endif
     23 
     24 #include "../GUI/ExtractRes.h"
     25 #include "resourceGui.h"
     26 
     27 #include "ExtractCallback.h"
     28 #include "FormatUtils.h"
     29 #include "LangUtils.h"
     30 #include "OverwriteDialog.h"
     31 #ifndef _NO_CRYPTO
     32 #include "PasswordDialog.h"
     33 #endif
     34 #include "PropertyName.h"
     35 
     36 using namespace NWindows;
     37 using namespace NFile;
     38 using namespace NFind;
     39 
     40 CExtractCallbackImp::~CExtractCallbackImp() {}
     41 
     42 void CExtractCallbackImp::Init()
     43 {
     44  _lang_Extracting = LangString(IDS_PROGRESS_EXTRACTING);
     45  _lang_Testing = LangString(IDS_PROGRESS_TESTING);
     46  _lang_Skipping = LangString(IDS_PROGRESS_SKIPPING);
     47 
     48  NumArchiveErrors = 0;
     49  ThereAreMessageErrors = false;
     50  #ifndef _SFX
     51  NumFolders = NumFiles = 0;
     52  NeedAddFile = false;
     53  #endif
     54 }
     55 
     56 void CExtractCallbackImp::AddError_Message(LPCWSTR s)
     57 {
     58  ThereAreMessageErrors = true;
     59  ProgressDialog->Sync.AddError_Message(s);
     60 }
     61 
     62 #ifndef _SFX
     63 
     64 STDMETHODIMP CExtractCallbackImp::SetNumFiles(UInt64
     65  #ifndef _SFX
     66  numFiles
     67  #endif
     68  )
     69 {
     70  #ifndef _SFX
     71  ProgressDialog->Sync.Set_NumFilesTotal(numFiles);
     72  #endif
     73  return S_OK;
     74 }
     75 
     76 #endif
     77 
     78 STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 total)
     79 {
     80  ProgressDialog->Sync.Set_NumBytesTotal(total);
     81  return S_OK;
     82 }
     83 
     84 STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *value)
     85 {
     86  return ProgressDialog->Sync.Set_NumBytesCur(value);
     87 }
     88 
     89 HRESULT CExtractCallbackImp::Open_CheckBreak()
     90 {
     91  return ProgressDialog->Sync.CheckStop();
     92 }
     93 
     94 HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *bytes)
     95 {
     96  HRESULT res = S_OK;
     97  if (!MultiArcMode)
     98  {
     99    if (files)
    100    {
    101      _totalFilesDefined = true;
    102      // res = ProgressDialog->Sync.Set_NumFilesTotal(*files);
    103    }
    104    else
    105      _totalFilesDefined = false;
    106 
    107    if (bytes)
    108    {
    109      _totalBytesDefined = true;
    110      ProgressDialog->Sync.Set_NumBytesTotal(*bytes);
    111    }
    112    else
    113      _totalBytesDefined = false;
    114  }
    115 
    116  return res;
    117 }
    118 
    119 HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes)
    120 {
    121  if (!MultiArcMode)
    122  {
    123    if (files)
    124    {
    125      ProgressDialog->Sync.Set_NumFilesCur(*files);
    126    }
    127 
    128    if (bytes)
    129    {
    130    }
    131  }
    132 
    133  return ProgressDialog->Sync.CheckStop();
    134 }
    135 
    136 HRESULT CExtractCallbackImp::Open_Finished()
    137 {
    138  return ProgressDialog->Sync.CheckStop();
    139 }
    140 
    141 #ifndef _NO_CRYPTO
    142 
    143 HRESULT CExtractCallbackImp::Open_CryptoGetTextPassword(BSTR *password)
    144 {
    145  return CryptoGetTextPassword(password);
    146 }
    147 
    148 /*
    149 HRESULT CExtractCallbackImp::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password)
    150 {
    151  passwordIsDefined = PasswordIsDefined;
    152  password = Password;
    153  return S_OK;
    154 }
    155 
    156 bool CExtractCallbackImp::Open_WasPasswordAsked()
    157 {
    158  return PasswordWasAsked;
    159 }
    160 
    161 void CExtractCallbackImp::Open_Clear_PasswordWasAsked_Flag()
    162 {
    163  PasswordWasAsked = false;
    164 }
    165 */
    166 
    167 #endif
    168 
    169 
    170 #ifndef _SFX
    171 STDMETHODIMP CExtractCallbackImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
    172 {
    173  ProgressDialog->Sync.Set_Ratio(inSize, outSize);
    174  return S_OK;
    175 }
    176 #endif
    177 
    178 /*
    179 STDMETHODIMP CExtractCallbackImp::SetTotalFiles(UInt64 total)
    180 {
    181  ProgressDialog->Sync.SetNumFilesTotal(total);
    182  return S_OK;
    183 }
    184 
    185 STDMETHODIMP CExtractCallbackImp::SetCompletedFiles(const UInt64 *value)
    186 {
    187  if (value != NULL)
    188    ProgressDialog->Sync.SetNumFilesCur(*value);
    189  return S_OK;
    190 }
    191 */
    192 
    193 STDMETHODIMP CExtractCallbackImp::AskOverwrite(
    194    const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
    195    const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
    196    Int32 *answer)
    197 {
    198  COverwriteDialog dialog;
    199 
    200  dialog.OldFileInfo.SetTime(existTime);
    201  dialog.OldFileInfo.SetSize(existSize);
    202  dialog.OldFileInfo.Name = existName;
    203 
    204  dialog.NewFileInfo.SetTime(newTime);
    205  dialog.NewFileInfo.SetSize(newSize);
    206  dialog.NewFileInfo.Name = newName;
    207  
    208  ProgressDialog->WaitCreating();
    209  INT_PTR writeAnswer = dialog.Create(*ProgressDialog);
    210  
    211  switch (writeAnswer)
    212  {
    213    case IDCANCEL:        *answer = NOverwriteAnswer::kCancel; return E_ABORT;
    214    case IDYES:           *answer = NOverwriteAnswer::kYes; break;
    215    case IDNO:            *answer = NOverwriteAnswer::kNo; break;
    216    case IDB_YES_TO_ALL:  *answer = NOverwriteAnswer::kYesToAll; break;
    217    case IDB_NO_TO_ALL:   *answer = NOverwriteAnswer::kNoToAll; break;
    218    case IDB_AUTO_RENAME: *answer = NOverwriteAnswer::kAutoRename; break;
    219    default: return E_FAIL;
    220  }
    221  return S_OK;
    222 }
    223 
    224 
    225 STDMETHODIMP CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 * /* position */)
    226 {
    227  _isFolder = IntToBool(isFolder);
    228  _currentFilePath = name;
    229 
    230  const UString *msg = &_lang_Empty;
    231  switch (askExtractMode)
    232  {
    233    case NArchive::NExtract::NAskMode::kExtract: msg = &_lang_Extracting; break;
    234    case NArchive::NExtract::NAskMode::kTest:    msg = &_lang_Testing; break;
    235    case NArchive::NExtract::NAskMode::kSkip:    msg = &_lang_Skipping; break;
    236    // default: s = "Unknown operation";
    237  }
    238 
    239  return ProgressDialog->Sync.Set_Status2(*msg, name, IntToBool(isFolder));
    240 }
    241 
    242 STDMETHODIMP CExtractCallbackImp::MessageError(const wchar_t *s)
    243 {
    244  AddError_Message(s);
    245  return S_OK;
    246 }
    247 
    248 HRESULT CExtractCallbackImp::MessageError(const char *message, const FString &path)
    249 {
    250  ThereAreMessageErrors = true;
    251  ProgressDialog->Sync.AddError_Message_Name(GetUnicodeString(message), fs2us(path));
    252  return S_OK;
    253 }
    254 
    255 #ifndef _SFX
    256 
    257 STDMETHODIMP CExtractCallbackImp::ShowMessage(const wchar_t *s)
    258 {
    259  AddError_Message(s);
    260  return S_OK;
    261 }
    262 
    263 #endif
    264 
    265 void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s)
    266 {
    267  s.Empty();
    268 
    269  if (opRes == NArchive::NExtract::NOperationResult::kOK)
    270    return;
    271 
    272  UINT messageID = 0;
    273  UINT id = 0;
    274 
    275  switch (opRes)
    276  {
    277    case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
    278      messageID = IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD;
    279      id = IDS_EXTRACT_MSG_UNSUPPORTED_METHOD;
    280      break;
    281    case NArchive::NExtract::NOperationResult::kDataError:
    282      messageID = encrypted ?
    283          IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED:
    284          IDS_EXTRACT_MESSAGE_DATA_ERROR;
    285      id = IDS_EXTRACT_MSG_DATA_ERROR;
    286      break;
    287    case NArchive::NExtract::NOperationResult::kCRCError:
    288      messageID = encrypted ?
    289          IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED:
    290          IDS_EXTRACT_MESSAGE_CRC_ERROR;
    291      id = IDS_EXTRACT_MSG_CRC_ERROR;
    292      break;
    293    case NArchive::NExtract::NOperationResult::kUnavailable:
    294      id = IDS_EXTRACT_MSG_UNAVAILABLE_DATA;
    295      break;
    296    case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
    297      id = IDS_EXTRACT_MSG_UEXPECTED_END;
    298      break;
    299    case NArchive::NExtract::NOperationResult::kDataAfterEnd:
    300      id = IDS_EXTRACT_MSG_DATA_AFTER_END;
    301      break;
    302    case NArchive::NExtract::NOperationResult::kIsNotArc:
    303      id = IDS_EXTRACT_MSG_IS_NOT_ARC;
    304      break;
    305    case NArchive::NExtract::NOperationResult::kHeadersError:
    306      id = IDS_EXTRACT_MSG_HEADERS_ERROR;
    307      break;
    308    case NArchive::NExtract::NOperationResult::kWrongPassword:
    309      id = IDS_EXTRACT_MSG_WRONG_PSW_CLAIM;
    310      break;
    311    /*
    312    default:
    313      messageID = IDS_EXTRACT_MESSAGE_UNKNOWN_ERROR;
    314      break;
    315    */
    316  }
    317 
    318  UString msg;
    319  UString msgOld;
    320 
    321  #ifndef _SFX
    322  if (id != 0)
    323    LangString_OnlyFromLangFile(id, msg);
    324  if (messageID != 0 && msg.IsEmpty())
    325    LangString_OnlyFromLangFile(messageID, msgOld);
    326  #endif
    327 
    328  if (msg.IsEmpty() && !msgOld.IsEmpty())
    329    s = MyFormatNew(msgOld, fileName);
    330  else
    331  {
    332    if (msg.IsEmpty() && id != 0)
    333      LangString(id, msg);
    334    if (!msg.IsEmpty())
    335      s += msg;
    336    else
    337    {
    338      s += "Error #";
    339      s.Add_UInt32(opRes);
    340    }
    341 
    342    if (encrypted && opRes != NArchive::NExtract::NOperationResult::kWrongPassword)
    343    {
    344      // s += " : ";
    345      // AddLangString(s, IDS_EXTRACT_MSG_ENCRYPTED);
    346      s += " : ";
    347      AddLangString(s, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
    348    }
    349    s += " : ";
    350    s += fileName;
    351  }
    352 }
    353 
    354 STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)
    355 {
    356  switch (opRes)
    357  {
    358    case NArchive::NExtract::NOperationResult::kOK:
    359      break;
    360    default:
    361    {
    362      UString s;
    363      SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s);
    364      Add_ArchiveName_Error();
    365      AddError_Message(s);
    366    }
    367  }
    368  
    369  #ifndef _SFX
    370  if (_isFolder)
    371    NumFolders++;
    372  else
    373    NumFiles++;
    374  ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
    375  #endif
    376  
    377  return S_OK;
    378 }
    379 
    380 STDMETHODIMP CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)
    381 {
    382  if (opRes != NArchive::NExtract::NOperationResult::kOK)
    383  {
    384    UString s;
    385    SetExtractErrorMessage(opRes, encrypted, name, s);
    386    Add_ArchiveName_Error();
    387    AddError_Message(s);
    388  }
    389  return S_OK;
    390 }
    391 
    392 ////////////////////////////////////////
    393 // IExtractCallbackUI
    394 
    395 HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */)
    396 {
    397  #ifndef _SFX
    398  RINOK(ProgressDialog->Sync.CheckStop());
    399  ProgressDialog->Sync.Set_TitleFileName(name);
    400  #endif
    401  _currentArchivePath = name;
    402  return S_OK;
    403 }
    404 
    405 HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path)
    406 {
    407  _currentFilePath = path;
    408  #ifndef _SFX
    409  ProgressDialog->Sync.Set_FilePath(path);
    410  #endif
    411  return S_OK;
    412 }
    413 
    414 #ifndef _SFX
    415 
    416 HRESULT CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path)
    417 {
    418  #ifndef _SFX
    419  if (NeedAddFile)
    420    NumFiles++;
    421  NeedAddFile = true;
    422  ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
    423  #endif
    424  return SetCurrentFilePath2(path);
    425 }
    426 
    427 #endif
    428 
    429 UString HResultToMessage(HRESULT errorCode);
    430 
    431 static const UInt32 k_ErrorFlagsIds[] =
    432 {
    433  IDS_EXTRACT_MSG_IS_NOT_ARC,
    434  IDS_EXTRACT_MSG_HEADERS_ERROR,
    435  IDS_EXTRACT_MSG_HEADERS_ERROR,
    436  IDS_OPEN_MSG_UNAVAILABLE_START,
    437  IDS_OPEN_MSG_UNCONFIRMED_START,
    438  IDS_EXTRACT_MSG_UEXPECTED_END,
    439  IDS_EXTRACT_MSG_DATA_AFTER_END,
    440  IDS_EXTRACT_MSG_UNSUPPORTED_METHOD,
    441  IDS_OPEN_MSG_UNSUPPORTED_FEATURE,
    442  IDS_EXTRACT_MSG_DATA_ERROR,
    443  IDS_EXTRACT_MSG_CRC_ERROR
    444 };
    445 
    446 static void AddNewLineString(UString &s, const UString &m)
    447 {
    448  s += m;
    449  s.Add_LF();
    450 }
    451 
    452 UString GetOpenArcErrorMessage(UInt32 errorFlags)
    453 {
    454  UString s;
    455 
    456  for (unsigned i = 0; i < ARRAY_SIZE(k_ErrorFlagsIds); i++)
    457  {
    458    UInt32 f = ((UInt32)1 << i);
    459    if ((errorFlags & f) == 0)
    460      continue;
    461    UInt32 id = k_ErrorFlagsIds[i];
    462    UString m = LangString(id);
    463    if (m.IsEmpty())
    464      continue;
    465    if (f == kpv_ErrorFlags_EncryptedHeadersError)
    466    {
    467      m += " : ";
    468      AddLangString(m, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
    469    }
    470    if (!s.IsEmpty())
    471      s.Add_LF();
    472    s += m;
    473    errorFlags &= ~f;
    474  }
    475  
    476  if (errorFlags != 0)
    477  {
    478    char sz[16];
    479    sz[0] = '0';
    480    sz[1] = 'x';
    481    ConvertUInt32ToHex(errorFlags, sz + 2);
    482    if (!s.IsEmpty())
    483      s.Add_LF();
    484    s += sz;
    485  }
    486  
    487  return s;
    488 }
    489 
    490 static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er)
    491 {
    492  UInt32 errorFlags = er.GetErrorFlags();
    493  UInt32 warningFlags = er.GetWarningFlags();
    494 
    495  if (errorFlags != 0)
    496    AddNewLineString(s, GetOpenArcErrorMessage(errorFlags));
    497      
    498  if (!er.ErrorMessage.IsEmpty())
    499    AddNewLineString(s, er.ErrorMessage);
    500  
    501  if (warningFlags != 0)
    502  {
    503    s += GetNameOfProperty(kpidWarningFlags, L"Warnings");
    504    s += ":";
    505    s.Add_LF();
    506    AddNewLineString(s, GetOpenArcErrorMessage(warningFlags));
    507  }
    508  
    509  if (!er.WarningMessage.IsEmpty())
    510  {
    511    s += GetNameOfProperty(kpidWarning, L"Warning");
    512    s += ": ";
    513    s += er.WarningMessage;
    514    s.Add_LF();
    515  }
    516 }
    517 
    518 static UString GetBracedType(const wchar_t *type)
    519 {
    520  UString s ('[');
    521  s += type;
    522  s += ']';
    523  return s;
    524 }
    525 
    526 void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
    527 {
    528  FOR_VECTOR (level, arcLink.Arcs)
    529  {
    530    const CArc &arc = arcLink.Arcs[level];
    531    const CArcErrorInfo &er = arc.ErrorInfo;
    532 
    533    if (!er.IsThereErrorOrWarning() && er.ErrorFormatIndex < 0)
    534      continue;
    535 
    536    if (s.IsEmpty())
    537    {
    538      s += name;
    539      s.Add_LF();
    540    }
    541    
    542    if (level != 0)
    543    {
    544      AddNewLineString(s, arc.Path);
    545    }
    546      
    547    ErrorInfo_Print(s, er);
    548 
    549    if (er.ErrorFormatIndex >= 0)
    550    {
    551      AddNewLineString(s, GetNameOfProperty(kpidWarning, L"Warning"));
    552      if (arc.FormatIndex == er.ErrorFormatIndex)
    553      {
    554        AddNewLineString(s, LangString(IDS_IS_OPEN_WITH_OFFSET));
    555      }
    556      else
    557      {
    558        AddNewLineString(s, MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(er.ErrorFormatIndex))));
    559        AddNewLineString(s, MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(arc.FormatIndex))));
    560      }
    561    }
    562  }
    563 
    564  if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result != S_OK)
    565  {
    566    s += name;
    567    s.Add_LF();
    568    if (!arcLink.Arcs.IsEmpty())
    569      AddNewLineString(s, arcLink.NonOpen_ArcPath);
    570    
    571    if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result == S_FALSE)
    572    {
    573      UINT id = IDS_CANT_OPEN_ARCHIVE;
    574      UString param;
    575      if (arcLink.PasswordWasAsked)
    576        id = IDS_CANT_OPEN_ENCRYPTED_ARCHIVE;
    577      else if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
    578      {
    579        id = IDS_CANT_OPEN_AS_TYPE;
    580        param = GetBracedType(codecs->GetFormatNamePtr(arcLink.NonOpen_ErrorInfo.ErrorFormatIndex));
    581      }
    582      UString s2 = MyFormatNew(id, param);
    583      s2.Replace(L" ''", L"");
    584      s2.Replace(L"''", L"");
    585      s += s2;
    586    }
    587    else
    588      s += HResultToMessage(result);
    589 
    590    s.Add_LF();
    591    ErrorInfo_Print(s, arcLink.NonOpen_ErrorInfo);
    592  }
    593 
    594  if (!s.IsEmpty() && s.Back() == '\n')
    595    s.DeleteBack();
    596 }
    597 
    598 HRESULT CExtractCallbackImp::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
    599 {
    600  _currentArchivePath = name;
    601  _needWriteArchivePath = true;
    602 
    603  UString s;
    604  OpenResult_GUI(s, codecs, arcLink, name, result);
    605  if (!s.IsEmpty())
    606  {
    607    NumArchiveErrors++;
    608    AddError_Message(s);
    609    _needWriteArchivePath = false;
    610  }
    611 
    612  return S_OK;
    613 }
    614 
    615 HRESULT CExtractCallbackImp::ThereAreNoFiles()
    616 {
    617  return S_OK;
    618 }
    619 
    620 void CExtractCallbackImp::Add_ArchiveName_Error()
    621 {
    622  if (_needWriteArchivePath)
    623  {
    624    if (!_currentArchivePath.IsEmpty())
    625      AddError_Message(_currentArchivePath);
    626    _needWriteArchivePath = false;
    627  }
    628 }
    629 
    630 HRESULT CExtractCallbackImp::ExtractResult(HRESULT result)
    631 {
    632  if (result == S_OK)
    633    return result;
    634  NumArchiveErrors++;
    635  if (result == E_ABORT || result == ERROR_DISK_FULL)
    636    return result;
    637 
    638  Add_ArchiveName_Error();
    639  if (!_currentFilePath.IsEmpty())
    640    MessageError(_currentFilePath);
    641  MessageError(NError::MyFormatMessage(result));
    642  return S_OK;
    643 }
    644 
    645 #ifndef _NO_CRYPTO
    646 
    647 HRESULT CExtractCallbackImp::SetPassword(const UString &password)
    648 {
    649  PasswordIsDefined = true;
    650  Password = password;
    651  return S_OK;
    652 }
    653 
    654 STDMETHODIMP CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)
    655 {
    656  PasswordWasAsked = true;
    657  if (!PasswordIsDefined)
    658  {
    659    CPasswordDialog dialog;
    660    #ifndef _SFX
    661    bool showPassword = NExtract::Read_ShowPassword();
    662    dialog.ShowPassword = showPassword;
    663    #endif
    664    ProgressDialog->WaitCreating();
    665    if (dialog.Create(*ProgressDialog) != IDOK)
    666      return E_ABORT;
    667    Password = dialog.Password;
    668    PasswordIsDefined = true;
    669    #ifndef _SFX
    670    if (dialog.ShowPassword != showPassword)
    671      NExtract::Save_ShowPassword(dialog.ShowPassword);
    672    #endif
    673  }
    674  return StringToBstr(Password, password);
    675 }
    676 
    677 #endif
    678 
    679 #ifndef _SFX
    680 
    681 STDMETHODIMP CExtractCallbackImp::AskWrite(
    682    const wchar_t *srcPath, Int32 srcIsFolder,
    683    const FILETIME *srcTime, const UInt64 *srcSize,
    684    const wchar_t *destPath,
    685    BSTR *destPathResult,
    686    Int32 *writeAnswer)
    687 {
    688  UString destPathResultTemp = destPath;
    689 
    690  // RINOK(StringToBstr(destPath, destPathResult));
    691 
    692  *destPathResult = 0;
    693  *writeAnswer = BoolToInt(false);
    694 
    695  FString destPathSys = us2fs(destPath);
    696  bool srcIsFolderSpec = IntToBool(srcIsFolder);
    697  CFileInfo destFileInfo;
    698  
    699  if (destFileInfo.Find(destPathSys))
    700  {
    701    if (srcIsFolderSpec)
    702    {
    703      if (!destFileInfo.IsDir())
    704      {
    705        RINOK(MessageError("can not replace file with folder with same name", destPathSys));
    706        return E_ABORT;
    707      }
    708      *writeAnswer = BoolToInt(false);
    709      return S_OK;
    710    }
    711  
    712    if (destFileInfo.IsDir())
    713    {
    714      RINOK(MessageError("can not replace folder with file with same name", destPathSys));
    715      *writeAnswer = BoolToInt(false);
    716      return S_OK;
    717    }
    718 
    719    switch (OverwriteMode)
    720    {
    721      case NExtract::NOverwriteMode::kSkip:
    722        return S_OK;
    723      case NExtract::NOverwriteMode::kAsk:
    724      {
    725        Int32 overwriteResult;
    726        UString destPathSpec = destPath;
    727        int slashPos = destPathSpec.ReverseFind_PathSepar();
    728        destPathSpec.DeleteFrom(slashPos + 1);
    729        destPathSpec += fs2us(destFileInfo.Name);
    730 
    731        RINOK(AskOverwrite(
    732            destPathSpec,
    733            &destFileInfo.MTime, &destFileInfo.Size,
    734            srcPath,
    735            srcTime, srcSize,
    736            &overwriteResult));
    737        
    738        switch (overwriteResult)
    739        {
    740          case NOverwriteAnswer::kCancel: return E_ABORT;
    741          case NOverwriteAnswer::kNo: return S_OK;
    742          case NOverwriteAnswer::kNoToAll: OverwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK;
    743          case NOverwriteAnswer::kYes: break;
    744          case NOverwriteAnswer::kYesToAll: OverwriteMode = NExtract::NOverwriteMode::kOverwrite; break;
    745          case NOverwriteAnswer::kAutoRename: OverwriteMode = NExtract::NOverwriteMode::kRename; break;
    746          default:
    747            return E_FAIL;
    748        }
    749      }
    750    }
    751    
    752    if (OverwriteMode == NExtract::NOverwriteMode::kRename)
    753    {
    754      if (!AutoRenamePath(destPathSys))
    755      {
    756        RINOK(MessageError("can not create name for file", destPathSys));
    757        return E_ABORT;
    758      }
    759      destPathResultTemp = fs2us(destPathSys);
    760    }
    761    else
    762      if (!NDir::DeleteFileAlways(destPathSys))
    763      {
    764        RINOK(MessageError("can not delete output file", destPathSys));
    765        return E_ABORT;
    766      }
    767  }
    768  *writeAnswer = BoolToInt(true);
    769  return StringToBstr(destPathResultTemp, destPathResult);
    770 }
    771 
    772 
    773 STDMETHODIMP CExtractCallbackImp::UseExtractToStream(Int32 *res)
    774 {
    775  *res = BoolToInt(StreamMode);
    776  return S_OK;
    777 }
    778 
    779 static HRESULT GetTime(IGetProp *getProp, PROPID propID, FILETIME &ft, bool &ftDefined)
    780 {
    781  ftDefined = false;
    782  NCOM::CPropVariant prop;
    783  RINOK(getProp->GetProp(propID, &prop));
    784  if (prop.vt == VT_FILETIME)
    785  {
    786    ft = prop.filetime;
    787    ftDefined = (ft.dwHighDateTime != 0 || ft.dwLowDateTime != 0);
    788  }
    789  else if (prop.vt != VT_EMPTY)
    790    return E_FAIL;
    791  return S_OK;
    792 }
    793 
    794 
    795 static HRESULT GetItemBoolProp(IGetProp *getProp, PROPID propID, bool &result)
    796 {
    797  NCOM::CPropVariant prop;
    798  result = false;
    799  RINOK(getProp->GetProp(propID, &prop));
    800  if (prop.vt == VT_BOOL)
    801    result = VARIANT_BOOLToBool(prop.boolVal);
    802  else if (prop.vt != VT_EMPTY)
    803    return E_FAIL;
    804  return S_OK;
    805 }
    806 
    807 
    808 STDMETHODIMP CExtractCallbackImp::GetStream7(const wchar_t *name,
    809    Int32 isDir,
    810    ISequentialOutStream **outStream, Int32 askExtractMode,
    811    IGetProp *getProp)
    812 {
    813  COM_TRY_BEGIN
    814  *outStream = 0;
    815  _newVirtFileWasAdded = false;
    816  _hashStreamWasUsed = false;
    817  _needUpdateStat = false;
    818 
    819  if (_hashStream)
    820    _hashStreamSpec->ReleaseStream();
    821 
    822  GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream);
    823 
    824  if (!ProcessAltStreams && _isAltStream)
    825    return S_OK;
    826 
    827  _filePath = name;
    828  _isFolder = IntToBool(isDir);
    829  _curSize = 0;
    830  _curSizeDefined = false;
    831 
    832  UInt64 size = 0;
    833  bool sizeDefined;
    834  {
    835    NCOM::CPropVariant prop;
    836    RINOK(getProp->GetProp(kpidSize, &prop));
    837    sizeDefined = ConvertPropVariantToUInt64(prop, size);
    838  }
    839 
    840  if (sizeDefined)
    841  {
    842    _curSize = size;
    843    _curSizeDefined = true;
    844  }
    845 
    846  if (askExtractMode != NArchive::NExtract::NAskMode::kExtract &&
    847      askExtractMode != NArchive::NExtract::NAskMode::kTest)
    848    return S_OK;
    849 
    850  _needUpdateStat = true;
    851  
    852  CMyComPtr<ISequentialOutStream> outStreamLoc;
    853  
    854  if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract)
    855  {
    856    CVirtFile &file = VirtFileSystemSpec->AddNewFile();
    857    _newVirtFileWasAdded = true;
    858    file.Name = name;
    859    file.IsDir = IntToBool(isDir);
    860    file.IsAltStream = _isAltStream;
    861    file.Size = 0;
    862 
    863    RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTimeDefined));
    864    RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATimeDefined));
    865    RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTimeDefined));
    866 
    867    NCOM::CPropVariant prop;
    868    RINOK(getProp->GetProp(kpidAttrib, &prop));
    869    if (prop.vt == VT_UI4)
    870    {
    871      file.Attrib = prop.ulVal;
    872      file.AttribDefined = true;
    873    }
    874    // else if (isDir) file.Attrib = FILE_ATTRIBUTE_DIRECTORY;
    875 
    876    file.ExpectedSize = 0;
    877    if (sizeDefined)
    878      file.ExpectedSize = size;
    879    outStreamLoc = VirtFileSystem;
    880  }
    881 
    882  if (_hashStream)
    883  {
    884    {
    885      _hashStreamSpec->SetStream(outStreamLoc);
    886      outStreamLoc = _hashStream;
    887      _hashStreamSpec->Init(true);
    888      _hashStreamWasUsed = true;
    889    }
    890  }
    891 
    892  if (outStreamLoc)
    893    *outStream = outStreamLoc.Detach();
    894  return S_OK;
    895  COM_TRY_END
    896 }
    897 
    898 STDMETHODIMP CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode)
    899 {
    900  COM_TRY_BEGIN
    901  _needUpdateStat = (
    902      askExtractMode == NArchive::NExtract::NAskMode::kExtract ||
    903      askExtractMode == NArchive::NExtract::NAskMode::kTest);
    904 
    905  /*
    906  _extractMode = false;
    907  switch (askExtractMode)
    908  {
    909    case NArchive::NExtract::NAskMode::kExtract:
    910      if (_testMode)
    911        askExtractMode = NArchive::NExtract::NAskMode::kTest;
    912      else
    913        _extractMode = true;
    914      break;
    915  };
    916  */
    917  return SetCurrentFilePath2(_filePath);
    918  COM_TRY_END
    919 }
    920 
    921 STDMETHODIMP CExtractCallbackImp::SetOperationResult7(Int32 opRes, Int32 encrypted)
    922 {
    923  COM_TRY_BEGIN
    924  if (VirtFileSystem && _newVirtFileWasAdded)
    925  {
    926    // FIXME: probably we must request file size from VirtFileSystem
    927    // _curSize = VirtFileSystem->GetLastFileSize()
    928    // _curSizeDefined = true;
    929    RINOK(VirtFileSystemSpec->CloseMemFile());
    930  }
    931  if (_hashStream && _hashStreamWasUsed)
    932  {
    933    _hashStreamSpec->_hash->Final(_isFolder, _isAltStream, _filePath);
    934    _curSize = _hashStreamSpec->GetSize();
    935    _curSizeDefined = true;
    936    _hashStreamSpec->ReleaseStream();
    937    _hashStreamWasUsed = false;
    938  }
    939  else if (_hashCalc && _needUpdateStat)
    940  {
    941    _hashCalc->SetSize(_curSize);
    942    _hashCalc->Final(_isFolder, _isAltStream, _filePath);
    943  }
    944  return SetOperationResult(opRes, encrypted);
    945  COM_TRY_END
    946 }
    947 
    948 
    949 static const size_t k_SizeT_MAX = (size_t)((size_t)0 - 1);
    950 
    951 static const UInt32 kBlockSize = ((UInt32)1 << 31);
    952 
    953 STDMETHODIMP CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize)
    954 {
    955  if (processedSize)
    956    *processedSize = 0;
    957  if (size == 0)
    958    return S_OK;
    959  if (!_fileMode)
    960  {
    961    CVirtFile &file = Files.Back();
    962    size_t rem = file.Data.Size() - (size_t)file.Size;
    963    bool useMem = true;
    964    if (rem < size)
    965    {
    966      UInt64 b = 0;
    967      if (file.Data.Size() == 0)
    968        b = file.ExpectedSize;
    969      UInt64 a = file.Size + size;
    970      if (b < a)
    971        b = a;
    972      a = (UInt64)file.Data.Size() * 2;
    973      if (b < a)
    974        b = a;
    975      useMem = false;
    976      if (b <= k_SizeT_MAX && b <= MaxTotalAllocSize)
    977        useMem = file.Data.ReAlloc_KeepData((size_t)b, (size_t)file.Size);
    978    }
    979    if (useMem)
    980    {
    981      memcpy(file.Data + file.Size, data, size);
    982      file.Size += size;
    983      if (processedSize)
    984        *processedSize = (UInt32)size;
    985      return S_OK;
    986    }
    987    _fileMode = true;
    988  }
    989  RINOK(FlushToDisk(false));
    990  return _outFileStream->Write(data, size, processedSize);
    991 }
    992 
    993 HRESULT CVirtFileSystem::FlushToDisk(bool closeLast)
    994 {
    995  if (!_outFileStream)
    996  {
    997    _outFileStreamSpec = new COutFileStream;
    998    _outFileStream = _outFileStreamSpec;
    999  }
   1000  while (_numFlushed < Files.Size())
   1001  {
   1002    const CVirtFile &file = Files[_numFlushed];
   1003    const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name));
   1004    if (!_fileIsOpen)
   1005    {
   1006      if (!_outFileStreamSpec->Create(path, false))
   1007      {
   1008        _outFileStream.Release();
   1009        return E_FAIL;
   1010        // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath));
   1011      }
   1012      _fileIsOpen = true;
   1013      RINOK(WriteStream(_outFileStream, file.Data, (size_t)file.Size));
   1014    }
   1015    if (_numFlushed == Files.Size() - 1 && !closeLast)
   1016      break;
   1017    if (file.CTimeDefined ||
   1018        file.ATimeDefined ||
   1019        file.MTimeDefined)
   1020      _outFileStreamSpec->SetTime(
   1021          file.CTimeDefined ? &file.CTime : NULL,
   1022          file.ATimeDefined ? &file.ATime : NULL,
   1023          file.MTimeDefined ? &file.MTime : NULL);
   1024    _outFileStreamSpec->Close();
   1025    _numFlushed++;
   1026    _fileIsOpen = false;
   1027    if (file.AttribDefined)
   1028      NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib);
   1029  }
   1030  return S_OK;
   1031 }
   1032 
   1033 #endif