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