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