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