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