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