• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~CExtractCallbackImp()40 CExtractCallbackImp::~CExtractCallbackImp() {}
41 
Init()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 
AddError_Message(LPCWSTR s)56 void CExtractCallbackImp::AddError_Message(LPCWSTR s)
57 {
58   ThereAreMessageErrors = true;
59   ProgressDialog->Sync.AddError_Message(s);
60 }
61 
62 #ifndef _SFX
63 
SetNumFiles(UInt64 numFiles)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 
SetTotal(UInt64 total)78 STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 total)
79 {
80   ProgressDialog->Sync.Set_NumBytesTotal(total);
81   return S_OK;
82 }
83 
SetCompleted(const UInt64 * value)84 STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *value)
85 {
86   return ProgressDialog->Sync.Set_NumBytesCur(value);
87 }
88 
Open_CheckBreak()89 HRESULT CExtractCallbackImp::Open_CheckBreak()
90 {
91   return ProgressDialog->Sync.CheckStop();
92 }
93 
Open_SetTotal(const UInt64 * files,const UInt64 * bytes)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 
Open_SetCompleted(const UInt64 * files,const UInt64 * bytes)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 
Open_Finished()136 HRESULT CExtractCallbackImp::Open_Finished()
137 {
138   return ProgressDialog->Sync.CheckStop();
139 }
140 
141 #ifndef _NO_CRYPTO
142 
Open_CryptoGetTextPassword(BSTR * password)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
SetRatioInfo(const UInt64 * inSize,const UInt64 * outSize)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 
AskOverwrite(const wchar_t * existName,const FILETIME * existTime,const UInt64 * existSize,const wchar_t * newName,const FILETIME * newTime,const UInt64 * newSize,Int32 * answer)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 
PrepareOperation(const wchar_t * name,Int32 isFolder,Int32 askExtractMode,const UInt64 *)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 
MessageError(const wchar_t * s)242 STDMETHODIMP CExtractCallbackImp::MessageError(const wchar_t *s)
243 {
244   AddError_Message(s);
245   return S_OK;
246 }
247 
MessageError(const char * message,const FString & path)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 
ShowMessage(const wchar_t * s)257 STDMETHODIMP CExtractCallbackImp::ShowMessage(const wchar_t *s)
258 {
259   AddError_Message(s);
260   return S_OK;
261 }
262 
263 #endif
264 
SetExtractErrorMessage(Int32 opRes,Int32 encrypted,const wchar_t * fileName,UString & s)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       char temp[16];
339       ConvertUInt32ToString(opRes, temp);
340       s.AddAscii("Error #");
341       s.AddAscii(temp);
342     }
343 
344     if (encrypted && opRes != NArchive::NExtract::NOperationResult::kWrongPassword)
345     {
346       // s.AddAscii(" : ");
347       // AddLangString(s, IDS_EXTRACT_MSG_ENCRYPTED);
348       s.AddAscii(" : ");
349       AddLangString(s, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
350     }
351     s.AddAscii(" : ");
352     s += fileName;
353   }
354 }
355 
SetOperationResult(Int32 opRes,Int32 encrypted)356 STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)
357 {
358   switch (opRes)
359   {
360     case NArchive::NExtract::NOperationResult::kOK:
361       break;
362     default:
363     {
364       UString s;
365       SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s);
366       Add_ArchiveName_Error();
367       AddError_Message(s);
368     }
369   }
370 
371   #ifndef _SFX
372   if (_isFolder)
373     NumFolders++;
374   else
375     NumFiles++;
376   ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
377   #endif
378 
379   return S_OK;
380 }
381 
ReportExtractResult(Int32 opRes,Int32 encrypted,const wchar_t * name)382 STDMETHODIMP CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)
383 {
384   if (opRes != NArchive::NExtract::NOperationResult::kOK)
385   {
386     UString s;
387     SetExtractErrorMessage(opRes, encrypted, name, s);
388     Add_ArchiveName_Error();
389     AddError_Message(s);
390   }
391   return S_OK;
392 }
393 
394 ////////////////////////////////////////
395 // IExtractCallbackUI
396 
BeforeOpen(const wchar_t * name,bool)397 HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */)
398 {
399   #ifndef _SFX
400   RINOK(ProgressDialog->Sync.CheckStop());
401   ProgressDialog->Sync.Set_TitleFileName(name);
402   #endif
403   _currentArchivePath = name;
404   return S_OK;
405 }
406 
SetCurrentFilePath2(const wchar_t * path)407 HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path)
408 {
409   _currentFilePath = path;
410   #ifndef _SFX
411   ProgressDialog->Sync.Set_FilePath(path);
412   #endif
413   return S_OK;
414 }
415 
416 #ifndef _SFX
417 
SetCurrentFilePath(const wchar_t * path)418 HRESULT CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path)
419 {
420   #ifndef _SFX
421   if (NeedAddFile)
422     NumFiles++;
423   NeedAddFile = true;
424   ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
425   #endif
426   return SetCurrentFilePath2(path);
427 }
428 
429 #endif
430 
431 UString HResultToMessage(HRESULT errorCode);
432 
433 static const UInt32 k_ErrorFlagsIds[] =
434 {
435   IDS_EXTRACT_MSG_IS_NOT_ARC,
436   IDS_EXTRACT_MSG_HEADERS_ERROR,
437   IDS_EXTRACT_MSG_HEADERS_ERROR,
438   IDS_OPEN_MSG_UNAVAILABLE_START,
439   IDS_OPEN_MSG_UNCONFIRMED_START,
440   IDS_EXTRACT_MSG_UEXPECTED_END,
441   IDS_EXTRACT_MSG_DATA_AFTER_END,
442   IDS_EXTRACT_MSG_UNSUPPORTED_METHOD,
443   IDS_OPEN_MSG_UNSUPPORTED_FEATURE,
444   IDS_EXTRACT_MSG_DATA_ERROR,
445   IDS_EXTRACT_MSG_CRC_ERROR
446 };
447 
AddNewLineString(UString & s,const UString & m)448 static void AddNewLineString(UString &s, const UString &m)
449 {
450   s += m;
451   s.Add_LF();
452 }
453 
GetOpenArcErrorMessage(UInt32 errorFlags)454 UString GetOpenArcErrorMessage(UInt32 errorFlags)
455 {
456   UString s;
457 
458   for (unsigned i = 0; i < ARRAY_SIZE(k_ErrorFlagsIds); i++)
459   {
460     UInt32 f = ((UInt32)1 << i);
461     if ((errorFlags & f) == 0)
462       continue;
463     UInt32 id = k_ErrorFlagsIds[i];
464     UString m = LangString(id);
465     if (m.IsEmpty())
466       continue;
467     if (f == kpv_ErrorFlags_EncryptedHeadersError)
468     {
469       m.AddAscii(" : ");
470       AddLangString(m, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
471     }
472     if (!s.IsEmpty())
473       s.Add_LF();
474     s += m;
475     errorFlags &= ~f;
476   }
477 
478   if (errorFlags != 0)
479   {
480     char sz[16];
481     sz[0] = '0';
482     sz[1] = 'x';
483     ConvertUInt32ToHex(errorFlags, sz + 2);
484     if (!s.IsEmpty())
485       s.Add_LF();
486     s.AddAscii(sz);
487   }
488 
489   return s;
490 }
491 
ErrorInfo_Print(UString & s,const CArcErrorInfo & er)492 static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er)
493 {
494   UInt32 errorFlags = er.GetErrorFlags();
495   UInt32 warningFlags = er.GetWarningFlags();
496 
497   if (errorFlags != 0)
498     AddNewLineString(s, GetOpenArcErrorMessage(errorFlags));
499 
500   if (!er.ErrorMessage.IsEmpty())
501     AddNewLineString(s, er.ErrorMessage);
502 
503   if (warningFlags != 0)
504   {
505     s += GetNameOfProperty(kpidWarningFlags, L"Warnings");
506     s.AddAscii(":");
507     s.Add_LF();
508     AddNewLineString(s, GetOpenArcErrorMessage(warningFlags));
509   }
510 
511   if (!er.WarningMessage.IsEmpty())
512   {
513     s += GetNameOfProperty(kpidWarning, L"Warning");
514     s.AddAscii(": ");
515     s += er.WarningMessage;
516     s.Add_LF();
517   }
518 }
519 
GetBracedType(const wchar_t * type)520 static UString GetBracedType(const wchar_t *type)
521 {
522   UString s = L'[';
523   s += type;
524   s += L']';
525   return s;
526 }
527 
OpenResult_GUI(UString & s,const CCodecs * codecs,const CArchiveLink & arcLink,const wchar_t * name,HRESULT result)528 void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
529 {
530   FOR_VECTOR (level, arcLink.Arcs)
531   {
532     const CArc &arc = arcLink.Arcs[level];
533     const CArcErrorInfo &er = arc.ErrorInfo;
534 
535     if (!er.IsThereErrorOrWarning() && er.ErrorFormatIndex < 0)
536       continue;
537 
538     if (s.IsEmpty())
539     {
540       s += name;
541       s.Add_LF();
542     }
543 
544     if (level != 0)
545     {
546       AddNewLineString(s, arc.Path);
547     }
548 
549     ErrorInfo_Print(s, er);
550 
551     if (er.ErrorFormatIndex >= 0)
552     {
553       AddNewLineString(s, GetNameOfProperty(kpidWarning, L"Warning"));
554       if (arc.FormatIndex == er.ErrorFormatIndex)
555       {
556         AddNewLineString(s, LangString(IDS_IS_OPEN_WITH_OFFSET));
557       }
558       else
559       {
560         AddNewLineString(s, MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(er.ErrorFormatIndex))));
561         AddNewLineString(s, MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(arc.FormatIndex))));
562       }
563     }
564   }
565 
566   if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result != S_OK)
567   {
568     s += name;
569     s.Add_LF();
570     if (!arcLink.Arcs.IsEmpty())
571       AddNewLineString(s, arcLink.NonOpen_ArcPath);
572 
573     if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result == S_FALSE)
574     {
575       UINT id = IDS_CANT_OPEN_ARCHIVE;
576       UString param;
577       if (arcLink.PasswordWasAsked)
578         id = IDS_CANT_OPEN_ENCRYPTED_ARCHIVE;
579       else if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
580       {
581         id = IDS_CANT_OPEN_AS_TYPE;
582         param = GetBracedType(codecs->GetFormatNamePtr(arcLink.NonOpen_ErrorInfo.ErrorFormatIndex));
583       }
584       UString s2 = MyFormatNew(id, param);
585       s2.Replace(L" ''", L"");
586       s2.Replace(L"''", L"");
587       s += s2;
588     }
589     else
590       s += HResultToMessage(result);
591 
592     s.Add_LF();
593     ErrorInfo_Print(s, arcLink.NonOpen_ErrorInfo);
594   }
595 
596   if (!s.IsEmpty() && s.Back() == '\n')
597     s.DeleteBack();
598 }
599 
OpenResult(const CCodecs * codecs,const CArchiveLink & arcLink,const wchar_t * name,HRESULT result)600 HRESULT CExtractCallbackImp::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
601 {
602   _currentArchivePath = name;
603   _needWriteArchivePath = true;
604 
605   UString s;
606   OpenResult_GUI(s, codecs, arcLink, name, result);
607   if (!s.IsEmpty())
608   {
609     NumArchiveErrors++;
610     AddError_Message(s);
611     _needWriteArchivePath = false;
612   }
613 
614   return S_OK;
615 }
616 
ThereAreNoFiles()617 HRESULT CExtractCallbackImp::ThereAreNoFiles()
618 {
619   return S_OK;
620 }
621 
Add_ArchiveName_Error()622 void CExtractCallbackImp::Add_ArchiveName_Error()
623 {
624   if (_needWriteArchivePath)
625   {
626     if (!_currentArchivePath.IsEmpty())
627       AddError_Message(_currentArchivePath);
628     _needWriteArchivePath = false;
629   }
630 }
631 
ExtractResult(HRESULT result)632 HRESULT CExtractCallbackImp::ExtractResult(HRESULT result)
633 {
634   if (result == S_OK)
635     return result;
636   NumArchiveErrors++;
637   if (result == E_ABORT || result == ERROR_DISK_FULL)
638     return result;
639 
640   Add_ArchiveName_Error();
641   if (!_currentFilePath.IsEmpty())
642     MessageError(_currentFilePath);
643   MessageError(NError::MyFormatMessage(result));
644   return S_OK;
645 }
646 
647 #ifndef _NO_CRYPTO
648 
SetPassword(const UString & password)649 HRESULT CExtractCallbackImp::SetPassword(const UString &password)
650 {
651   PasswordIsDefined = true;
652   Password = password;
653   return S_OK;
654 }
655 
CryptoGetTextPassword(BSTR * password)656 STDMETHODIMP CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)
657 {
658   PasswordWasAsked = true;
659   if (!PasswordIsDefined)
660   {
661     CPasswordDialog dialog;
662     #ifndef _SFX
663     bool showPassword = NExtract::Read_ShowPassword();
664     dialog.ShowPassword = showPassword;
665     #endif
666     ProgressDialog->WaitCreating();
667     if (dialog.Create(*ProgressDialog) != IDOK)
668       return E_ABORT;
669     Password = dialog.Password;
670     PasswordIsDefined = true;
671     #ifndef _SFX
672     if (dialog.ShowPassword != showPassword)
673       NExtract::Save_ShowPassword(dialog.ShowPassword);
674     #endif
675   }
676   return StringToBstr(Password, password);
677 }
678 
679 #endif
680 
681 #ifndef _SFX
682 
AskWrite(const wchar_t * srcPath,Int32 srcIsFolder,const FILETIME * srcTime,const UInt64 * srcSize,const wchar_t * destPath,BSTR * destPathResult,Int32 * writeAnswer)683 STDMETHODIMP CExtractCallbackImp::AskWrite(
684     const wchar_t *srcPath, Int32 srcIsFolder,
685     const FILETIME *srcTime, const UInt64 *srcSize,
686     const wchar_t *destPath,
687     BSTR *destPathResult,
688     Int32 *writeAnswer)
689 {
690   UString destPathResultTemp = destPath;
691 
692   // RINOK(StringToBstr(destPath, destPathResult));
693 
694   *destPathResult = 0;
695   *writeAnswer = BoolToInt(false);
696 
697   FString destPathSys = us2fs(destPath);
698   bool srcIsFolderSpec = IntToBool(srcIsFolder);
699   CFileInfo destFileInfo;
700 
701   if (destFileInfo.Find(destPathSys))
702   {
703     if (srcIsFolderSpec)
704     {
705       if (!destFileInfo.IsDir())
706       {
707         RINOK(MessageError("can not replace file with folder with same name", destPathSys));
708         return E_ABORT;
709       }
710       *writeAnswer = BoolToInt(false);
711       return S_OK;
712     }
713 
714     if (destFileInfo.IsDir())
715     {
716       RINOK(MessageError("can not replace folder with file with same name", destPathSys));
717       *writeAnswer = BoolToInt(false);
718       return S_OK;
719     }
720 
721     switch (OverwriteMode)
722     {
723       case NExtract::NOverwriteMode::kSkip:
724         return S_OK;
725       case NExtract::NOverwriteMode::kAsk:
726       {
727         Int32 overwriteResult;
728         UString destPathSpec = destPath;
729         int slashPos = destPathSpec.ReverseFind_PathSepar();
730         destPathSpec.DeleteFrom(slashPos + 1);
731         destPathSpec += fs2us(destFileInfo.Name);
732 
733         RINOK(AskOverwrite(
734             destPathSpec,
735             &destFileInfo.MTime, &destFileInfo.Size,
736             srcPath,
737             srcTime, srcSize,
738             &overwriteResult));
739 
740         switch (overwriteResult)
741         {
742           case NOverwriteAnswer::kCancel: return E_ABORT;
743           case NOverwriteAnswer::kNo: return S_OK;
744           case NOverwriteAnswer::kNoToAll: OverwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK;
745           case NOverwriteAnswer::kYes: break;
746           case NOverwriteAnswer::kYesToAll: OverwriteMode = NExtract::NOverwriteMode::kOverwrite; break;
747           case NOverwriteAnswer::kAutoRename: OverwriteMode = NExtract::NOverwriteMode::kRename; break;
748           default:
749             return E_FAIL;
750         }
751       }
752     }
753 
754     if (OverwriteMode == NExtract::NOverwriteMode::kRename)
755     {
756       if (!AutoRenamePath(destPathSys))
757       {
758         RINOK(MessageError("can not create name for file", destPathSys));
759         return E_ABORT;
760       }
761       destPathResultTemp = fs2us(destPathSys);
762     }
763     else
764       if (!NDir::DeleteFileAlways(destPathSys))
765       {
766         RINOK(MessageError("can not delete output file", destPathSys));
767         return E_ABORT;
768       }
769   }
770   *writeAnswer = BoolToInt(true);
771   return StringToBstr(destPathResultTemp, destPathResult);
772 }
773 
774 
UseExtractToStream(Int32 * res)775 STDMETHODIMP CExtractCallbackImp::UseExtractToStream(Int32 *res)
776 {
777   *res = BoolToInt(StreamMode);
778   return S_OK;
779 }
780 
GetTime(IGetProp * getProp,PROPID propID,FILETIME & ft,bool & ftDefined)781 static HRESULT GetTime(IGetProp *getProp, PROPID propID, FILETIME &ft, bool &ftDefined)
782 {
783   ftDefined = false;
784   NCOM::CPropVariant prop;
785   RINOK(getProp->GetProp(propID, &prop));
786   if (prop.vt == VT_FILETIME)
787   {
788     ft = prop.filetime;
789     ftDefined = (ft.dwHighDateTime != 0 || ft.dwLowDateTime != 0);
790   }
791   else if (prop.vt != VT_EMPTY)
792     return E_FAIL;
793   return S_OK;
794 }
795 
796 
GetItemBoolProp(IGetProp * getProp,PROPID propID,bool & result)797 static HRESULT GetItemBoolProp(IGetProp *getProp, PROPID propID, bool &result)
798 {
799   NCOM::CPropVariant prop;
800   result = false;
801   RINOK(getProp->GetProp(propID, &prop));
802   if (prop.vt == VT_BOOL)
803     result = VARIANT_BOOLToBool(prop.boolVal);
804   else if (prop.vt != VT_EMPTY)
805     return E_FAIL;
806   return S_OK;
807 }
808 
809 
GetStream7(const wchar_t * name,Int32 isDir,ISequentialOutStream ** outStream,Int32 askExtractMode,IGetProp * getProp)810 STDMETHODIMP CExtractCallbackImp::GetStream7(const wchar_t *name,
811     Int32 isDir,
812     ISequentialOutStream **outStream, Int32 askExtractMode,
813     IGetProp *getProp)
814 {
815   COM_TRY_BEGIN
816   *outStream = 0;
817   _newVirtFileWasAdded = false;
818   _hashStreamWasUsed = false;
819   _needUpdateStat = false;
820 
821   if (_hashStream)
822     _hashStreamSpec->ReleaseStream();
823 
824   GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream);
825 
826   if (!ProcessAltStreams && _isAltStream)
827     return S_OK;
828 
829   _filePath = name;
830   _isFolder = IntToBool(isDir);
831   _curSize = 0;
832   _curSizeDefined = false;
833 
834   UInt64 size = 0;
835   bool sizeDefined;
836   {
837     NCOM::CPropVariant prop;
838     RINOK(getProp->GetProp(kpidSize, &prop));
839     sizeDefined = ConvertPropVariantToUInt64(prop, size);
840   }
841 
842   if (sizeDefined)
843   {
844     _curSize = size;
845     _curSizeDefined = true;
846   }
847 
848   if (askExtractMode != NArchive::NExtract::NAskMode::kExtract &&
849       askExtractMode != NArchive::NExtract::NAskMode::kTest)
850     return S_OK;
851 
852   _needUpdateStat = true;
853 
854   CMyComPtr<ISequentialOutStream> outStreamLoc;
855 
856   if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract)
857   {
858     CVirtFile &file = VirtFileSystemSpec->AddNewFile();
859     _newVirtFileWasAdded = true;
860     file.Name = name;
861     file.IsDir = IntToBool(isDir);
862     file.IsAltStream = _isAltStream;
863     file.Size = 0;
864 
865     RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTimeDefined));
866     RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATimeDefined));
867     RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTimeDefined));
868 
869     NCOM::CPropVariant prop;
870     RINOK(getProp->GetProp(kpidAttrib, &prop));
871     if (prop.vt == VT_UI4)
872     {
873       file.Attrib = prop.ulVal;
874       file.AttribDefined = true;
875     }
876     // else if (isDir) file.Attrib = FILE_ATTRIBUTE_DIRECTORY;
877 
878     file.ExpectedSize = 0;
879     if (sizeDefined)
880       file.ExpectedSize = size;
881     outStreamLoc = VirtFileSystem;
882   }
883 
884   if (_hashStream)
885   {
886     {
887       _hashStreamSpec->SetStream(outStreamLoc);
888       outStreamLoc = _hashStream;
889       _hashStreamSpec->Init(true);
890       _hashStreamWasUsed = true;
891     }
892   }
893 
894   if (outStreamLoc)
895     *outStream = outStreamLoc.Detach();
896   return S_OK;
897   COM_TRY_END
898 }
899 
PrepareOperation7(Int32 askExtractMode)900 STDMETHODIMP CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode)
901 {
902   COM_TRY_BEGIN
903   _needUpdateStat = (
904       askExtractMode == NArchive::NExtract::NAskMode::kExtract ||
905       askExtractMode == NArchive::NExtract::NAskMode::kTest);
906 
907   /*
908   _extractMode = false;
909   switch (askExtractMode)
910   {
911     case NArchive::NExtract::NAskMode::kExtract:
912       if (_testMode)
913         askExtractMode = NArchive::NExtract::NAskMode::kTest;
914       else
915         _extractMode = true;
916       break;
917   };
918   */
919   return SetCurrentFilePath2(_filePath);
920   COM_TRY_END
921 }
922 
SetOperationResult7(Int32 opRes,Int32 encrypted)923 STDMETHODIMP CExtractCallbackImp::SetOperationResult7(Int32 opRes, Int32 encrypted)
924 {
925   COM_TRY_BEGIN
926   if (VirtFileSystem && _newVirtFileWasAdded)
927   {
928     // FIXME: probably we must request file size from VirtFileSystem
929     // _curSize = VirtFileSystem->GetLastFileSize()
930     // _curSizeDefined = true;
931     RINOK(VirtFileSystemSpec->CloseMemFile());
932   }
933   if (_hashStream && _hashStreamWasUsed)
934   {
935     _hashStreamSpec->_hash->Final(_isFolder, _isAltStream, _filePath);
936     _curSize = _hashStreamSpec->GetSize();
937     _curSizeDefined = true;
938     _hashStreamSpec->ReleaseStream();
939     _hashStreamWasUsed = false;
940   }
941   else if (_hashCalc && _needUpdateStat)
942   {
943     _hashCalc->SetSize(_curSize);
944     _hashCalc->Final(_isFolder, _isAltStream, _filePath);
945   }
946   return SetOperationResult(opRes, encrypted);
947   COM_TRY_END
948 }
949 
950 
951 static const size_t k_SizeT_MAX = (size_t)((size_t)0 - 1);
952 
953 static const UInt32 kBlockSize = ((UInt32)1 << 31);
954 
Write(const void * data,UInt32 size,UInt32 * processedSize)955 STDMETHODIMP CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize)
956 {
957   if (processedSize)
958     *processedSize = 0;
959   if (size == 0)
960     return S_OK;
961   if (!_fileMode)
962   {
963     CVirtFile &file = Files.Back();
964     size_t rem = file.Data.Size() - (size_t)file.Size;
965     bool useMem = true;
966     if (rem < size)
967     {
968       UInt64 b = 0;
969       if (file.Data.Size() == 0)
970         b = file.ExpectedSize;
971       UInt64 a = file.Size + size;
972       if (b < a)
973         b = a;
974       a = (UInt64)file.Data.Size() * 2;
975       if (b < a)
976         b = a;
977       useMem = false;
978       if (b <= k_SizeT_MAX && b <= MaxTotalAllocSize)
979         useMem = file.Data.ReAlloc_KeepData((size_t)b, (size_t)file.Size);
980     }
981     if (useMem)
982     {
983       memcpy(file.Data + file.Size, data, size);
984       file.Size += size;
985       if (processedSize)
986         *processedSize = (UInt32)size;
987       return S_OK;
988     }
989     _fileMode = true;
990   }
991   RINOK(FlushToDisk(false));
992   return _outFileStream->Write(data, size, processedSize);
993 }
994 
FlushToDisk(bool closeLast)995 HRESULT CVirtFileSystem::FlushToDisk(bool closeLast)
996 {
997   if (!_outFileStream)
998   {
999     _outFileStreamSpec = new COutFileStream;
1000     _outFileStream = _outFileStreamSpec;
1001   }
1002   while (_numFlushed < Files.Size())
1003   {
1004     const CVirtFile &file = Files[_numFlushed];
1005     const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name));
1006     if (!_fileIsOpen)
1007     {
1008       if (!_outFileStreamSpec->Create(path, false))
1009       {
1010         _outFileStream.Release();
1011         return E_FAIL;
1012         // MessageBoxMyError(UString(L"Can't create file ") + fs2us(tempFilePath));
1013       }
1014       _fileIsOpen = true;
1015       RINOK(WriteStream(_outFileStream, file.Data, (size_t)file.Size));
1016     }
1017     if (_numFlushed == Files.Size() - 1 && !closeLast)
1018       break;
1019     if (file.CTimeDefined ||
1020         file.ATimeDefined ||
1021         file.MTimeDefined)
1022       _outFileStreamSpec->SetTime(
1023           file.CTimeDefined ? &file.CTime : NULL,
1024           file.ATimeDefined ? &file.ATime : NULL,
1025           file.MTimeDefined ? &file.MTime : NULL);
1026     _outFileStreamSpec->Close();
1027     _numFlushed++;
1028     _fileIsOpen = false;
1029     if (file.AttribDefined)
1030       NDir::SetFileAttrib(path, file.Attrib);
1031   }
1032   return S_OK;
1033 }
1034 
1035 #endif
1036