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 char temp[16];
339 ConvertUInt32ToString(opRes, temp);
340 s.AddAscii("Error #");
341 s.AddAscii(temp);
342 }
343
344 if (encrypted && opRes != NArchive::NExtract::NOperationResult::kWrongPassword)
345 {
346 // s.AddAscii(" : ");
347 // AddLangString(s, IDS_EXTRACT_MSG_ENCRYPTED);
348 s.AddAscii(" : ");
349 AddLangString(s, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
350 }
351 s.AddAscii(" : ");
352 s += fileName;
353 }
354 }
355
SetOperationResult(Int32 opRes,Int32 encrypted)356 STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)
357 {
358 switch (opRes)
359 {
360 case NArchive::NExtract::NOperationResult::kOK:
361 break;
362 default:
363 {
364 UString s;
365 SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s);
366 Add_ArchiveName_Error();
367 AddError_Message(s);
368 }
369 }
370
371 #ifndef _SFX
372 if (_isFolder)
373 NumFolders++;
374 else
375 NumFiles++;
376 ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
377 #endif
378
379 return S_OK;
380 }
381
ReportExtractResult(Int32 opRes,Int32 encrypted,const wchar_t * name)382 STDMETHODIMP CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)
383 {
384 if (opRes != NArchive::NExtract::NOperationResult::kOK)
385 {
386 UString s;
387 SetExtractErrorMessage(opRes, encrypted, name, s);
388 Add_ArchiveName_Error();
389 AddError_Message(s);
390 }
391 return S_OK;
392 }
393
394 ////////////////////////////////////////
395 // IExtractCallbackUI
396
BeforeOpen(const wchar_t * name,bool)397 HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */)
398 {
399 #ifndef _SFX
400 RINOK(ProgressDialog->Sync.CheckStop());
401 ProgressDialog->Sync.Set_TitleFileName(name);
402 #endif
403 _currentArchivePath = name;
404 return S_OK;
405 }
406
SetCurrentFilePath2(const wchar_t * path)407 HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path)
408 {
409 _currentFilePath = path;
410 #ifndef _SFX
411 ProgressDialog->Sync.Set_FilePath(path);
412 #endif
413 return S_OK;
414 }
415
416 #ifndef _SFX
417
SetCurrentFilePath(const wchar_t * path)418 HRESULT CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path)
419 {
420 #ifndef _SFX
421 if (NeedAddFile)
422 NumFiles++;
423 NeedAddFile = true;
424 ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
425 #endif
426 return SetCurrentFilePath2(path);
427 }
428
429 #endif
430
431 UString HResultToMessage(HRESULT errorCode);
432
433 static const UInt32 k_ErrorFlagsIds[] =
434 {
435 IDS_EXTRACT_MSG_IS_NOT_ARC,
436 IDS_EXTRACT_MSG_HEADERS_ERROR,
437 IDS_EXTRACT_MSG_HEADERS_ERROR,
438 IDS_OPEN_MSG_UNAVAILABLE_START,
439 IDS_OPEN_MSG_UNCONFIRMED_START,
440 IDS_EXTRACT_MSG_UEXPECTED_END,
441 IDS_EXTRACT_MSG_DATA_AFTER_END,
442 IDS_EXTRACT_MSG_UNSUPPORTED_METHOD,
443 IDS_OPEN_MSG_UNSUPPORTED_FEATURE,
444 IDS_EXTRACT_MSG_DATA_ERROR,
445 IDS_EXTRACT_MSG_CRC_ERROR
446 };
447
AddNewLineString(UString & s,const UString & m)448 static void AddNewLineString(UString &s, const UString &m)
449 {
450 s += m;
451 s.Add_LF();
452 }
453
GetOpenArcErrorMessage(UInt32 errorFlags)454 UString GetOpenArcErrorMessage(UInt32 errorFlags)
455 {
456 UString s;
457
458 for (unsigned i = 0; i < ARRAY_SIZE(k_ErrorFlagsIds); i++)
459 {
460 UInt32 f = ((UInt32)1 << i);
461 if ((errorFlags & f) == 0)
462 continue;
463 UInt32 id = k_ErrorFlagsIds[i];
464 UString m = LangString(id);
465 if (m.IsEmpty())
466 continue;
467 if (f == kpv_ErrorFlags_EncryptedHeadersError)
468 {
469 m.AddAscii(" : ");
470 AddLangString(m, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
471 }
472 if (!s.IsEmpty())
473 s.Add_LF();
474 s += m;
475 errorFlags &= ~f;
476 }
477
478 if (errorFlags != 0)
479 {
480 char sz[16];
481 sz[0] = '0';
482 sz[1] = 'x';
483 ConvertUInt32ToHex(errorFlags, sz + 2);
484 if (!s.IsEmpty())
485 s.Add_LF();
486 s.AddAscii(sz);
487 }
488
489 return s;
490 }
491
ErrorInfo_Print(UString & s,const CArcErrorInfo & er)492 static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er)
493 {
494 UInt32 errorFlags = er.GetErrorFlags();
495 UInt32 warningFlags = er.GetWarningFlags();
496
497 if (errorFlags != 0)
498 AddNewLineString(s, GetOpenArcErrorMessage(errorFlags));
499
500 if (!er.ErrorMessage.IsEmpty())
501 AddNewLineString(s, er.ErrorMessage);
502
503 if (warningFlags != 0)
504 {
505 s += GetNameOfProperty(kpidWarningFlags, L"Warnings");
506 s.AddAscii(":");
507 s.Add_LF();
508 AddNewLineString(s, GetOpenArcErrorMessage(warningFlags));
509 }
510
511 if (!er.WarningMessage.IsEmpty())
512 {
513 s += GetNameOfProperty(kpidWarning, L"Warning");
514 s.AddAscii(": ");
515 s += er.WarningMessage;
516 s.Add_LF();
517 }
518 }
519
GetBracedType(const wchar_t * type)520 static UString GetBracedType(const wchar_t *type)
521 {
522 UString s = L'[';
523 s += type;
524 s += L']';
525 return s;
526 }
527
OpenResult_GUI(UString & s,const CCodecs * codecs,const CArchiveLink & arcLink,const wchar_t * name,HRESULT result)528 void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
529 {
530 FOR_VECTOR (level, arcLink.Arcs)
531 {
532 const CArc &arc = arcLink.Arcs[level];
533 const CArcErrorInfo &er = arc.ErrorInfo;
534
535 if (!er.IsThereErrorOrWarning() && er.ErrorFormatIndex < 0)
536 continue;
537
538 if (s.IsEmpty())
539 {
540 s += name;
541 s.Add_LF();
542 }
543
544 if (level != 0)
545 {
546 AddNewLineString(s, arc.Path);
547 }
548
549 ErrorInfo_Print(s, er);
550
551 if (er.ErrorFormatIndex >= 0)
552 {
553 AddNewLineString(s, GetNameOfProperty(kpidWarning, L"Warning"));
554 if (arc.FormatIndex == er.ErrorFormatIndex)
555 {
556 AddNewLineString(s, LangString(IDS_IS_OPEN_WITH_OFFSET));
557 }
558 else
559 {
560 AddNewLineString(s, MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(er.ErrorFormatIndex))));
561 AddNewLineString(s, MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(arc.FormatIndex))));
562 }
563 }
564 }
565
566 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result != S_OK)
567 {
568 s += name;
569 s.Add_LF();
570 if (!arcLink.Arcs.IsEmpty())
571 AddNewLineString(s, arcLink.NonOpen_ArcPath);
572
573 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result == S_FALSE)
574 {
575 UINT id = IDS_CANT_OPEN_ARCHIVE;
576 UString param;
577 if (arcLink.PasswordWasAsked)
578 id = IDS_CANT_OPEN_ENCRYPTED_ARCHIVE;
579 else if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
580 {
581 id = IDS_CANT_OPEN_AS_TYPE;
582 param = GetBracedType(codecs->GetFormatNamePtr(arcLink.NonOpen_ErrorInfo.ErrorFormatIndex));
583 }
584 UString s2 = MyFormatNew(id, param);
585 s2.Replace(L" ''", L"");
586 s2.Replace(L"''", L"");
587 s += s2;
588 }
589 else
590 s += HResultToMessage(result);
591
592 s.Add_LF();
593 ErrorInfo_Print(s, arcLink.NonOpen_ErrorInfo);
594 }
595
596 if (!s.IsEmpty() && s.Back() == '\n')
597 s.DeleteBack();
598 }
599
OpenResult(const CCodecs * codecs,const CArchiveLink & arcLink,const wchar_t * name,HRESULT result)600 HRESULT CExtractCallbackImp::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
601 {
602 _currentArchivePath = name;
603 _needWriteArchivePath = true;
604
605 UString s;
606 OpenResult_GUI(s, codecs, arcLink, name, result);
607 if (!s.IsEmpty())
608 {
609 NumArchiveErrors++;
610 AddError_Message(s);
611 _needWriteArchivePath = false;
612 }
613
614 return S_OK;
615 }
616
ThereAreNoFiles()617 HRESULT CExtractCallbackImp::ThereAreNoFiles()
618 {
619 return S_OK;
620 }
621
Add_ArchiveName_Error()622 void CExtractCallbackImp::Add_ArchiveName_Error()
623 {
624 if (_needWriteArchivePath)
625 {
626 if (!_currentArchivePath.IsEmpty())
627 AddError_Message(_currentArchivePath);
628 _needWriteArchivePath = false;
629 }
630 }
631
ExtractResult(HRESULT result)632 HRESULT CExtractCallbackImp::ExtractResult(HRESULT result)
633 {
634 if (result == S_OK)
635 return result;
636 NumArchiveErrors++;
637 if (result == E_ABORT || result == ERROR_DISK_FULL)
638 return result;
639
640 Add_ArchiveName_Error();
641 if (!_currentFilePath.IsEmpty())
642 MessageError(_currentFilePath);
643 MessageError(NError::MyFormatMessage(result));
644 return S_OK;
645 }
646
647 #ifndef _NO_CRYPTO
648
SetPassword(const UString & password)649 HRESULT CExtractCallbackImp::SetPassword(const UString &password)
650 {
651 PasswordIsDefined = true;
652 Password = password;
653 return S_OK;
654 }
655
CryptoGetTextPassword(BSTR * password)656 STDMETHODIMP CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)
657 {
658 PasswordWasAsked = true;
659 if (!PasswordIsDefined)
660 {
661 CPasswordDialog dialog;
662 #ifndef _SFX
663 bool showPassword = NExtract::Read_ShowPassword();
664 dialog.ShowPassword = showPassword;
665 #endif
666 ProgressDialog->WaitCreating();
667 if (dialog.Create(*ProgressDialog) != IDOK)
668 return E_ABORT;
669 Password = dialog.Password;
670 PasswordIsDefined = true;
671 #ifndef _SFX
672 if (dialog.ShowPassword != showPassword)
673 NExtract::Save_ShowPassword(dialog.ShowPassword);
674 #endif
675 }
676 return StringToBstr(Password, password);
677 }
678
679 #endif
680
681 #ifndef _SFX
682
AskWrite(const wchar_t * srcPath,Int32 srcIsFolder,const FILETIME * srcTime,const UInt64 * srcSize,const wchar_t * destPath,BSTR * destPathResult,Int32 * writeAnswer)683 STDMETHODIMP CExtractCallbackImp::AskWrite(
684 const wchar_t *srcPath, Int32 srcIsFolder,
685 const FILETIME *srcTime, const UInt64 *srcSize,
686 const wchar_t *destPath,
687 BSTR *destPathResult,
688 Int32 *writeAnswer)
689 {
690 UString destPathResultTemp = destPath;
691
692 // RINOK(StringToBstr(destPath, destPathResult));
693
694 *destPathResult = 0;
695 *writeAnswer = BoolToInt(false);
696
697 FString destPathSys = us2fs(destPath);
698 bool srcIsFolderSpec = IntToBool(srcIsFolder);
699 CFileInfo destFileInfo;
700
701 if (destFileInfo.Find(destPathSys))
702 {
703 if (srcIsFolderSpec)
704 {
705 if (!destFileInfo.IsDir())
706 {
707 RINOK(MessageError("can not replace file with folder with same name", destPathSys));
708 return E_ABORT;
709 }
710 *writeAnswer = BoolToInt(false);
711 return S_OK;
712 }
713
714 if (destFileInfo.IsDir())
715 {
716 RINOK(MessageError("can not replace folder with file with same name", destPathSys));
717 *writeAnswer = BoolToInt(false);
718 return S_OK;
719 }
720
721 switch (OverwriteMode)
722 {
723 case NExtract::NOverwriteMode::kSkip:
724 return S_OK;
725 case NExtract::NOverwriteMode::kAsk:
726 {
727 Int32 overwriteResult;
728 UString destPathSpec = destPath;
729 int slashPos = destPathSpec.ReverseFind_PathSepar();
730 destPathSpec.DeleteFrom(slashPos + 1);
731 destPathSpec += fs2us(destFileInfo.Name);
732
733 RINOK(AskOverwrite(
734 destPathSpec,
735 &destFileInfo.MTime, &destFileInfo.Size,
736 srcPath,
737 srcTime, srcSize,
738 &overwriteResult));
739
740 switch (overwriteResult)
741 {
742 case NOverwriteAnswer::kCancel: return E_ABORT;
743 case NOverwriteAnswer::kNo: return S_OK;
744 case NOverwriteAnswer::kNoToAll: OverwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK;
745 case NOverwriteAnswer::kYes: break;
746 case NOverwriteAnswer::kYesToAll: OverwriteMode = NExtract::NOverwriteMode::kOverwrite; break;
747 case NOverwriteAnswer::kAutoRename: OverwriteMode = NExtract::NOverwriteMode::kRename; break;
748 default:
749 return E_FAIL;
750 }
751 }
752 }
753
754 if (OverwriteMode == NExtract::NOverwriteMode::kRename)
755 {
756 if (!AutoRenamePath(destPathSys))
757 {
758 RINOK(MessageError("can not create name for file", destPathSys));
759 return E_ABORT;
760 }
761 destPathResultTemp = fs2us(destPathSys);
762 }
763 else
764 if (!NDir::DeleteFileAlways(destPathSys))
765 {
766 RINOK(MessageError("can not delete output file", destPathSys));
767 return E_ABORT;
768 }
769 }
770 *writeAnswer = BoolToInt(true);
771 return StringToBstr(destPathResultTemp, destPathResult);
772 }
773
774
UseExtractToStream(Int32 * res)775 STDMETHODIMP CExtractCallbackImp::UseExtractToStream(Int32 *res)
776 {
777 *res = BoolToInt(StreamMode);
778 return S_OK;
779 }
780
GetTime(IGetProp * getProp,PROPID propID,FILETIME & ft,bool & ftDefined)781 static HRESULT GetTime(IGetProp *getProp, PROPID propID, FILETIME &ft, bool &ftDefined)
782 {
783 ftDefined = false;
784 NCOM::CPropVariant prop;
785 RINOK(getProp->GetProp(propID, &prop));
786 if (prop.vt == VT_FILETIME)
787 {
788 ft = prop.filetime;
789 ftDefined = (ft.dwHighDateTime != 0 || ft.dwLowDateTime != 0);
790 }
791 else if (prop.vt != VT_EMPTY)
792 return E_FAIL;
793 return S_OK;
794 }
795
796
GetItemBoolProp(IGetProp * getProp,PROPID propID,bool & result)797 static HRESULT GetItemBoolProp(IGetProp *getProp, PROPID propID, bool &result)
798 {
799 NCOM::CPropVariant prop;
800 result = false;
801 RINOK(getProp->GetProp(propID, &prop));
802 if (prop.vt == VT_BOOL)
803 result = VARIANT_BOOLToBool(prop.boolVal);
804 else if (prop.vt != VT_EMPTY)
805 return E_FAIL;
806 return S_OK;
807 }
808
809
GetStream7(const wchar_t * name,Int32 isDir,ISequentialOutStream ** outStream,Int32 askExtractMode,IGetProp * getProp)810 STDMETHODIMP CExtractCallbackImp::GetStream7(const wchar_t *name,
811 Int32 isDir,
812 ISequentialOutStream **outStream, Int32 askExtractMode,
813 IGetProp *getProp)
814 {
815 COM_TRY_BEGIN
816 *outStream = 0;
817 _newVirtFileWasAdded = false;
818 _hashStreamWasUsed = false;
819 _needUpdateStat = false;
820
821 if (_hashStream)
822 _hashStreamSpec->ReleaseStream();
823
824 GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream);
825
826 if (!ProcessAltStreams && _isAltStream)
827 return S_OK;
828
829 _filePath = name;
830 _isFolder = IntToBool(isDir);
831 _curSize = 0;
832 _curSizeDefined = false;
833
834 UInt64 size = 0;
835 bool sizeDefined;
836 {
837 NCOM::CPropVariant prop;
838 RINOK(getProp->GetProp(kpidSize, &prop));
839 sizeDefined = ConvertPropVariantToUInt64(prop, size);
840 }
841
842 if (sizeDefined)
843 {
844 _curSize = size;
845 _curSizeDefined = true;
846 }
847
848 if (askExtractMode != NArchive::NExtract::NAskMode::kExtract &&
849 askExtractMode != NArchive::NExtract::NAskMode::kTest)
850 return S_OK;
851
852 _needUpdateStat = true;
853
854 CMyComPtr<ISequentialOutStream> outStreamLoc;
855
856 if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract)
857 {
858 CVirtFile &file = VirtFileSystemSpec->AddNewFile();
859 _newVirtFileWasAdded = true;
860 file.Name = name;
861 file.IsDir = IntToBool(isDir);
862 file.IsAltStream = _isAltStream;
863 file.Size = 0;
864
865 RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTimeDefined));
866 RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATimeDefined));
867 RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTimeDefined));
868
869 NCOM::CPropVariant prop;
870 RINOK(getProp->GetProp(kpidAttrib, &prop));
871 if (prop.vt == VT_UI4)
872 {
873 file.Attrib = prop.ulVal;
874 file.AttribDefined = true;
875 }
876 // else if (isDir) file.Attrib = FILE_ATTRIBUTE_DIRECTORY;
877
878 file.ExpectedSize = 0;
879 if (sizeDefined)
880 file.ExpectedSize = size;
881 outStreamLoc = VirtFileSystem;
882 }
883
884 if (_hashStream)
885 {
886 {
887 _hashStreamSpec->SetStream(outStreamLoc);
888 outStreamLoc = _hashStream;
889 _hashStreamSpec->Init(true);
890 _hashStreamWasUsed = true;
891 }
892 }
893
894 if (outStreamLoc)
895 *outStream = outStreamLoc.Detach();
896 return S_OK;
897 COM_TRY_END
898 }
899
PrepareOperation7(Int32 askExtractMode)900 STDMETHODIMP CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode)
901 {
902 COM_TRY_BEGIN
903 _needUpdateStat = (
904 askExtractMode == NArchive::NExtract::NAskMode::kExtract ||
905 askExtractMode == NArchive::NExtract::NAskMode::kTest);
906
907 /*
908 _extractMode = false;
909 switch (askExtractMode)
910 {
911 case NArchive::NExtract::NAskMode::kExtract:
912 if (_testMode)
913 askExtractMode = NArchive::NExtract::NAskMode::kTest;
914 else
915 _extractMode = true;
916 break;
917 };
918 */
919 return SetCurrentFilePath2(_filePath);
920 COM_TRY_END
921 }
922
SetOperationResult7(Int32 opRes,Int32 encrypted)923 STDMETHODIMP CExtractCallbackImp::SetOperationResult7(Int32 opRes, Int32 encrypted)
924 {
925 COM_TRY_BEGIN
926 if (VirtFileSystem && _newVirtFileWasAdded)
927 {
928 // FIXME: probably we must request file size from VirtFileSystem
929 // _curSize = VirtFileSystem->GetLastFileSize()
930 // _curSizeDefined = true;
931 RINOK(VirtFileSystemSpec->CloseMemFile());
932 }
933 if (_hashStream && _hashStreamWasUsed)
934 {
935 _hashStreamSpec->_hash->Final(_isFolder, _isAltStream, _filePath);
936 _curSize = _hashStreamSpec->GetSize();
937 _curSizeDefined = true;
938 _hashStreamSpec->ReleaseStream();
939 _hashStreamWasUsed = false;
940 }
941 else if (_hashCalc && _needUpdateStat)
942 {
943 _hashCalc->SetSize(_curSize);
944 _hashCalc->Final(_isFolder, _isAltStream, _filePath);
945 }
946 return SetOperationResult(opRes, encrypted);
947 COM_TRY_END
948 }
949
950
951 static const size_t k_SizeT_MAX = (size_t)((size_t)0 - 1);
952
953 static const UInt32 kBlockSize = ((UInt32)1 << 31);
954
Write(const void * data,UInt32 size,UInt32 * processedSize)955 STDMETHODIMP CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize)
956 {
957 if (processedSize)
958 *processedSize = 0;
959 if (size == 0)
960 return S_OK;
961 if (!_fileMode)
962 {
963 CVirtFile &file = Files.Back();
964 size_t rem = file.Data.Size() - (size_t)file.Size;
965 bool useMem = true;
966 if (rem < size)
967 {
968 UInt64 b = 0;
969 if (file.Data.Size() == 0)
970 b = file.ExpectedSize;
971 UInt64 a = file.Size + size;
972 if (b < a)
973 b = a;
974 a = (UInt64)file.Data.Size() * 2;
975 if (b < a)
976 b = a;
977 useMem = false;
978 if (b <= k_SizeT_MAX && b <= MaxTotalAllocSize)
979 useMem = file.Data.ReAlloc_KeepData((size_t)b, (size_t)file.Size);
980 }
981 if (useMem)
982 {
983 memcpy(file.Data + file.Size, data, size);
984 file.Size += size;
985 if (processedSize)
986 *processedSize = (UInt32)size;
987 return S_OK;
988 }
989 _fileMode = true;
990 }
991 RINOK(FlushToDisk(false));
992 return _outFileStream->Write(data, size, processedSize);
993 }
994
FlushToDisk(bool closeLast)995 HRESULT CVirtFileSystem::FlushToDisk(bool closeLast)
996 {
997 if (!_outFileStream)
998 {
999 _outFileStreamSpec = new COutFileStream;
1000 _outFileStream = _outFileStreamSpec;
1001 }
1002 while (_numFlushed < Files.Size())
1003 {
1004 const CVirtFile &file = Files[_numFlushed];
1005 const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name));
1006 if (!_fileIsOpen)
1007 {
1008 if (!_outFileStreamSpec->Create(path, false))
1009 {
1010 _outFileStream.Release();
1011 return E_FAIL;
1012 // MessageBoxMyError(UString(L"Can't create file ") + fs2us(tempFilePath));
1013 }
1014 _fileIsOpen = true;
1015 RINOK(WriteStream(_outFileStream, file.Data, (size_t)file.Size));
1016 }
1017 if (_numFlushed == Files.Size() - 1 && !closeLast)
1018 break;
1019 if (file.CTimeDefined ||
1020 file.ATimeDefined ||
1021 file.MTimeDefined)
1022 _outFileStreamSpec->SetTime(
1023 file.CTimeDefined ? &file.CTime : NULL,
1024 file.ATimeDefined ? &file.ATime : NULL,
1025 file.MTimeDefined ? &file.MTime : NULL);
1026 _outFileStreamSpec->Close();
1027 _numFlushed++;
1028 _fileIsOpen = false;
1029 if (file.AttribDefined)
1030 NDir::SetFileAttrib(path, file.Attrib);
1031 }
1032 return S_OK;
1033 }
1034
1035 #endif
1036