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