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