// ExtractCallback.cpp #include "StdAfx.h" #include "../../../Common/ComTry.h" #include "../../../Common/IntToString.h" #include "../../../Common/Lang.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/ErrorMsg.h" #include "../../../Windows/FileDir.h" #include "../../../Windows/FileFind.h" #include "../../../Windows/PropVariantConv.h" #include "../../Common/FilePathAutoRename.h" #include "../../Common/StreamUtils.h" #include "../Common/ExtractingFilePath.h" #ifndef _SFX #include "../Common/ZipRegistry.h" #endif #include "../GUI/ExtractRes.h" #include "resourceGui.h" #include "ExtractCallback.h" #include "FormatUtils.h" #include "LangUtils.h" #include "OverwriteDialog.h" #ifndef _NO_CRYPTO #include "PasswordDialog.h" #endif #include "PropertyName.h" using namespace NWindows; using namespace NFile; using namespace NFind; CExtractCallbackImp::~CExtractCallbackImp() {} void CExtractCallbackImp::Init() { _lang_Extracting = LangString(IDS_PROGRESS_EXTRACTING); _lang_Testing = LangString(IDS_PROGRESS_TESTING); _lang_Skipping = LangString(IDS_PROGRESS_SKIPPING); NumArchiveErrors = 0; ThereAreMessageErrors = false; #ifndef _SFX NumFolders = NumFiles = 0; NeedAddFile = false; #endif } void CExtractCallbackImp::AddError_Message(LPCWSTR s) { ThereAreMessageErrors = true; ProgressDialog->Sync.AddError_Message(s); } #ifndef _SFX STDMETHODIMP CExtractCallbackImp::SetNumFiles(UInt64 #ifndef _SFX numFiles #endif ) { #ifndef _SFX ProgressDialog->Sync.Set_NumFilesTotal(numFiles); #endif return S_OK; } #endif STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 total) { ProgressDialog->Sync.Set_NumBytesTotal(total); return S_OK; } STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *value) { return ProgressDialog->Sync.Set_NumBytesCur(value); } HRESULT CExtractCallbackImp::Open_CheckBreak() { return ProgressDialog->Sync.CheckStop(); } HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *bytes) { HRESULT res = S_OK; if (!MultiArcMode) { if (files) { _totalFilesDefined = true; // res = ProgressDialog->Sync.Set_NumFilesTotal(*files); } else _totalFilesDefined = false; if (bytes) { _totalBytesDefined = true; ProgressDialog->Sync.Set_NumBytesTotal(*bytes); } else _totalBytesDefined = false; } return res; } HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) { if (!MultiArcMode) { if (files) { ProgressDialog->Sync.Set_NumFilesCur(*files); } if (bytes) { } } return ProgressDialog->Sync.CheckStop(); } HRESULT CExtractCallbackImp::Open_Finished() { return ProgressDialog->Sync.CheckStop(); } #ifndef _NO_CRYPTO HRESULT CExtractCallbackImp::Open_CryptoGetTextPassword(BSTR *password) { return CryptoGetTextPassword(password); } /* HRESULT CExtractCallbackImp::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) { passwordIsDefined = PasswordIsDefined; password = Password; return S_OK; } bool CExtractCallbackImp::Open_WasPasswordAsked() { return PasswordWasAsked; } void CExtractCallbackImp::Open_Clear_PasswordWasAsked_Flag() { PasswordWasAsked = false; } */ #endif #ifndef _SFX STDMETHODIMP CExtractCallbackImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) { ProgressDialog->Sync.Set_Ratio(inSize, outSize); return S_OK; } #endif /* STDMETHODIMP CExtractCallbackImp::SetTotalFiles(UInt64 total) { ProgressDialog->Sync.SetNumFilesTotal(total); return S_OK; } STDMETHODIMP CExtractCallbackImp::SetCompletedFiles(const UInt64 *value) { if (value != NULL) ProgressDialog->Sync.SetNumFilesCur(*value); return S_OK; } */ STDMETHODIMP CExtractCallbackImp::AskOverwrite( const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, Int32 *answer) { COverwriteDialog dialog; dialog.OldFileInfo.SetTime(existTime); dialog.OldFileInfo.SetSize(existSize); dialog.OldFileInfo.Name = existName; dialog.NewFileInfo.SetTime(newTime); dialog.NewFileInfo.SetSize(newSize); dialog.NewFileInfo.Name = newName; ProgressDialog->WaitCreating(); INT_PTR writeAnswer = dialog.Create(*ProgressDialog); switch (writeAnswer) { case IDCANCEL: *answer = NOverwriteAnswer::kCancel; return E_ABORT; case IDYES: *answer = NOverwriteAnswer::kYes; break; case IDNO: *answer = NOverwriteAnswer::kNo; break; case IDB_YES_TO_ALL: *answer = NOverwriteAnswer::kYesToAll; break; case IDB_NO_TO_ALL: *answer = NOverwriteAnswer::kNoToAll; break; case IDB_AUTO_RENAME: *answer = NOverwriteAnswer::kAutoRename; break; default: return E_FAIL; } return S_OK; } STDMETHODIMP CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 * /* position */) { _isFolder = IntToBool(isFolder); _currentFilePath = name; const UString *msg = &_lang_Empty; switch (askExtractMode) { case NArchive::NExtract::NAskMode::kExtract: msg = &_lang_Extracting; break; case NArchive::NExtract::NAskMode::kTest: msg = &_lang_Testing; break; case NArchive::NExtract::NAskMode::kSkip: msg = &_lang_Skipping; break; // default: s = "Unknown operation"; } return ProgressDialog->Sync.Set_Status2(*msg, name, IntToBool(isFolder)); } STDMETHODIMP CExtractCallbackImp::MessageError(const wchar_t *s) { AddError_Message(s); return S_OK; } HRESULT CExtractCallbackImp::MessageError(const char *message, const FString &path) { ThereAreMessageErrors = true; ProgressDialog->Sync.AddError_Message_Name(GetUnicodeString(message), fs2us(path)); return S_OK; } #ifndef _SFX STDMETHODIMP CExtractCallbackImp::ShowMessage(const wchar_t *s) { AddError_Message(s); return S_OK; } #endif void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s) { s.Empty(); if (opRes == NArchive::NExtract::NOperationResult::kOK) return; UINT messageID = 0; UINT id = 0; switch (opRes) { case NArchive::NExtract::NOperationResult::kUnsupportedMethod: messageID = IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD; id = IDS_EXTRACT_MSG_UNSUPPORTED_METHOD; break; case NArchive::NExtract::NOperationResult::kDataError: messageID = encrypted ? IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED: IDS_EXTRACT_MESSAGE_DATA_ERROR; id = IDS_EXTRACT_MSG_DATA_ERROR; break; case NArchive::NExtract::NOperationResult::kCRCError: messageID = encrypted ? IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED: IDS_EXTRACT_MESSAGE_CRC_ERROR; id = IDS_EXTRACT_MSG_CRC_ERROR; break; case NArchive::NExtract::NOperationResult::kUnavailable: id = IDS_EXTRACT_MSG_UNAVAILABLE_DATA; break; case NArchive::NExtract::NOperationResult::kUnexpectedEnd: id = IDS_EXTRACT_MSG_UEXPECTED_END; break; case NArchive::NExtract::NOperationResult::kDataAfterEnd: id = IDS_EXTRACT_MSG_DATA_AFTER_END; break; case NArchive::NExtract::NOperationResult::kIsNotArc: id = IDS_EXTRACT_MSG_IS_NOT_ARC; break; case NArchive::NExtract::NOperationResult::kHeadersError: id = IDS_EXTRACT_MSG_HEADERS_ERROR; break; case NArchive::NExtract::NOperationResult::kWrongPassword: id = IDS_EXTRACT_MSG_WRONG_PSW_CLAIM; break; /* default: messageID = IDS_EXTRACT_MESSAGE_UNKNOWN_ERROR; break; */ } UString msg; UString msgOld; #ifndef _SFX if (id != 0) LangString_OnlyFromLangFile(id, msg); if (messageID != 0 && msg.IsEmpty()) LangString_OnlyFromLangFile(messageID, msgOld); #endif if (msg.IsEmpty() && !msgOld.IsEmpty()) s = MyFormatNew(msgOld, fileName); else { if (msg.IsEmpty() && id != 0) LangString(id, msg); if (!msg.IsEmpty()) s += msg; else { s += "Error #"; s.Add_UInt32(opRes); } if (encrypted && opRes != NArchive::NExtract::NOperationResult::kWrongPassword) { // s += " : "; // AddLangString(s, IDS_EXTRACT_MSG_ENCRYPTED); s += " : "; AddLangString(s, IDS_EXTRACT_MSG_WRONG_PSW_GUESS); } s += " : "; s += fileName; } } STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted) { switch (opRes) { case NArchive::NExtract::NOperationResult::kOK: break; default: { UString s; SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s); Add_ArchiveName_Error(); AddError_Message(s); } } #ifndef _SFX if (_isFolder) NumFolders++; else NumFiles++; ProgressDialog->Sync.Set_NumFilesCur(NumFiles); #endif return S_OK; } STDMETHODIMP CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name) { if (opRes != NArchive::NExtract::NOperationResult::kOK) { UString s; SetExtractErrorMessage(opRes, encrypted, name, s); Add_ArchiveName_Error(); AddError_Message(s); } return S_OK; } //////////////////////////////////////// // IExtractCallbackUI HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */) { #ifndef _SFX RINOK(ProgressDialog->Sync.CheckStop()); ProgressDialog->Sync.Set_TitleFileName(name); #endif _currentArchivePath = name; return S_OK; } HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path) { _currentFilePath = path; #ifndef _SFX ProgressDialog->Sync.Set_FilePath(path); #endif return S_OK; } #ifndef _SFX HRESULT CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path) { #ifndef _SFX if (NeedAddFile) NumFiles++; NeedAddFile = true; ProgressDialog->Sync.Set_NumFilesCur(NumFiles); #endif return SetCurrentFilePath2(path); } #endif UString HResultToMessage(HRESULT errorCode); static const UInt32 k_ErrorFlagsIds[] = { IDS_EXTRACT_MSG_IS_NOT_ARC, IDS_EXTRACT_MSG_HEADERS_ERROR, IDS_EXTRACT_MSG_HEADERS_ERROR, IDS_OPEN_MSG_UNAVAILABLE_START, IDS_OPEN_MSG_UNCONFIRMED_START, IDS_EXTRACT_MSG_UEXPECTED_END, IDS_EXTRACT_MSG_DATA_AFTER_END, IDS_EXTRACT_MSG_UNSUPPORTED_METHOD, IDS_OPEN_MSG_UNSUPPORTED_FEATURE, IDS_EXTRACT_MSG_DATA_ERROR, IDS_EXTRACT_MSG_CRC_ERROR }; static void AddNewLineString(UString &s, const UString &m) { s += m; s.Add_LF(); } UString GetOpenArcErrorMessage(UInt32 errorFlags) { UString s; for (unsigned i = 0; i < ARRAY_SIZE(k_ErrorFlagsIds); i++) { UInt32 f = ((UInt32)1 << i); if ((errorFlags & f) == 0) continue; UInt32 id = k_ErrorFlagsIds[i]; UString m = LangString(id); if (m.IsEmpty()) continue; if (f == kpv_ErrorFlags_EncryptedHeadersError) { m += " : "; AddLangString(m, IDS_EXTRACT_MSG_WRONG_PSW_GUESS); } if (!s.IsEmpty()) s.Add_LF(); s += m; errorFlags &= ~f; } if (errorFlags != 0) { char sz[16]; sz[0] = '0'; sz[1] = 'x'; ConvertUInt32ToHex(errorFlags, sz + 2); if (!s.IsEmpty()) s.Add_LF(); s += sz; } return s; } static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er) { UInt32 errorFlags = er.GetErrorFlags(); UInt32 warningFlags = er.GetWarningFlags(); if (errorFlags != 0) AddNewLineString(s, GetOpenArcErrorMessage(errorFlags)); if (!er.ErrorMessage.IsEmpty()) AddNewLineString(s, er.ErrorMessage); if (warningFlags != 0) { s += GetNameOfProperty(kpidWarningFlags, L"Warnings"); s += ":"; s.Add_LF(); AddNewLineString(s, GetOpenArcErrorMessage(warningFlags)); } if (!er.WarningMessage.IsEmpty()) { s += GetNameOfProperty(kpidWarning, L"Warning"); s += ": "; s += er.WarningMessage; s.Add_LF(); } } static UString GetBracedType(const wchar_t *type) { UString s ('['); s += type; s += ']'; return s; } void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) { FOR_VECTOR (level, arcLink.Arcs) { const CArc &arc = arcLink.Arcs[level]; const CArcErrorInfo &er = arc.ErrorInfo; if (!er.IsThereErrorOrWarning() && er.ErrorFormatIndex < 0) continue; if (s.IsEmpty()) { s += name; s.Add_LF(); } if (level != 0) { AddNewLineString(s, arc.Path); } ErrorInfo_Print(s, er); if (er.ErrorFormatIndex >= 0) { AddNewLineString(s, GetNameOfProperty(kpidWarning, L"Warning")); if (arc.FormatIndex == er.ErrorFormatIndex) { AddNewLineString(s, LangString(IDS_IS_OPEN_WITH_OFFSET)); } else { AddNewLineString(s, MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(er.ErrorFormatIndex)))); AddNewLineString(s, MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(arc.FormatIndex)))); } } } if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result != S_OK) { s += name; s.Add_LF(); if (!arcLink.Arcs.IsEmpty()) AddNewLineString(s, arcLink.NonOpen_ArcPath); if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result == S_FALSE) { UINT id = IDS_CANT_OPEN_ARCHIVE; UString param; if (arcLink.PasswordWasAsked) id = IDS_CANT_OPEN_ENCRYPTED_ARCHIVE; else if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) { id = IDS_CANT_OPEN_AS_TYPE; param = GetBracedType(codecs->GetFormatNamePtr(arcLink.NonOpen_ErrorInfo.ErrorFormatIndex)); } UString s2 = MyFormatNew(id, param); s2.Replace(L" ''", L""); s2.Replace(L"''", L""); s += s2; } else s += HResultToMessage(result); s.Add_LF(); ErrorInfo_Print(s, arcLink.NonOpen_ErrorInfo); } if (!s.IsEmpty() && s.Back() == '\n') s.DeleteBack(); } HRESULT CExtractCallbackImp::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) { _currentArchivePath = name; _needWriteArchivePath = true; UString s; OpenResult_GUI(s, codecs, arcLink, name, result); if (!s.IsEmpty()) { NumArchiveErrors++; AddError_Message(s); _needWriteArchivePath = false; } return S_OK; } HRESULT CExtractCallbackImp::ThereAreNoFiles() { return S_OK; } void CExtractCallbackImp::Add_ArchiveName_Error() { if (_needWriteArchivePath) { if (!_currentArchivePath.IsEmpty()) AddError_Message(_currentArchivePath); _needWriteArchivePath = false; } } HRESULT CExtractCallbackImp::ExtractResult(HRESULT result) { if (result == S_OK) return result; NumArchiveErrors++; if (result == E_ABORT || result == ERROR_DISK_FULL) return result; Add_ArchiveName_Error(); if (!_currentFilePath.IsEmpty()) MessageError(_currentFilePath); MessageError(NError::MyFormatMessage(result)); return S_OK; } #ifndef _NO_CRYPTO HRESULT CExtractCallbackImp::SetPassword(const UString &password) { PasswordIsDefined = true; Password = password; return S_OK; } STDMETHODIMP CExtractCallbackImp::CryptoGetTextPassword(BSTR *password) { PasswordWasAsked = true; if (!PasswordIsDefined) { CPasswordDialog dialog; #ifndef _SFX bool showPassword = NExtract::Read_ShowPassword(); dialog.ShowPassword = showPassword; #endif ProgressDialog->WaitCreating(); if (dialog.Create(*ProgressDialog) != IDOK) return E_ABORT; Password = dialog.Password; PasswordIsDefined = true; #ifndef _SFX if (dialog.ShowPassword != showPassword) NExtract::Save_ShowPassword(dialog.ShowPassword); #endif } return StringToBstr(Password, password); } #endif #ifndef _SFX STDMETHODIMP CExtractCallbackImp::AskWrite( const wchar_t *srcPath, Int32 srcIsFolder, const FILETIME *srcTime, const UInt64 *srcSize, const wchar_t *destPath, BSTR *destPathResult, Int32 *writeAnswer) { UString destPathResultTemp = destPath; // RINOK(StringToBstr(destPath, destPathResult)); *destPathResult = 0; *writeAnswer = BoolToInt(false); FString destPathSys = us2fs(destPath); bool srcIsFolderSpec = IntToBool(srcIsFolder); CFileInfo destFileInfo; if (destFileInfo.Find(destPathSys)) { if (srcIsFolderSpec) { if (!destFileInfo.IsDir()) { RINOK(MessageError("can not replace file with folder with same name", destPathSys)); return E_ABORT; } *writeAnswer = BoolToInt(false); return S_OK; } if (destFileInfo.IsDir()) { RINOK(MessageError("can not replace folder with file with same name", destPathSys)); *writeAnswer = BoolToInt(false); return S_OK; } switch (OverwriteMode) { case NExtract::NOverwriteMode::kSkip: return S_OK; case NExtract::NOverwriteMode::kAsk: { Int32 overwriteResult; UString destPathSpec = destPath; int slashPos = destPathSpec.ReverseFind_PathSepar(); destPathSpec.DeleteFrom(slashPos + 1); destPathSpec += fs2us(destFileInfo.Name); RINOK(AskOverwrite( destPathSpec, &destFileInfo.MTime, &destFileInfo.Size, srcPath, srcTime, srcSize, &overwriteResult)); switch (overwriteResult) { case NOverwriteAnswer::kCancel: return E_ABORT; case NOverwriteAnswer::kNo: return S_OK; case NOverwriteAnswer::kNoToAll: OverwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK; case NOverwriteAnswer::kYes: break; case NOverwriteAnswer::kYesToAll: OverwriteMode = NExtract::NOverwriteMode::kOverwrite; break; case NOverwriteAnswer::kAutoRename: OverwriteMode = NExtract::NOverwriteMode::kRename; break; default: return E_FAIL; } } } if (OverwriteMode == NExtract::NOverwriteMode::kRename) { if (!AutoRenamePath(destPathSys)) { RINOK(MessageError("can not create name for file", destPathSys)); return E_ABORT; } destPathResultTemp = fs2us(destPathSys); } else if (!NDir::DeleteFileAlways(destPathSys)) { RINOK(MessageError("can not delete output file", destPathSys)); return E_ABORT; } } *writeAnswer = BoolToInt(true); return StringToBstr(destPathResultTemp, destPathResult); } STDMETHODIMP CExtractCallbackImp::UseExtractToStream(Int32 *res) { *res = BoolToInt(StreamMode); return S_OK; } static HRESULT GetTime(IGetProp *getProp, PROPID propID, FILETIME &ft, bool &ftDefined) { ftDefined = false; NCOM::CPropVariant prop; RINOK(getProp->GetProp(propID, &prop)); if (prop.vt == VT_FILETIME) { ft = prop.filetime; ftDefined = (ft.dwHighDateTime != 0 || ft.dwLowDateTime != 0); } else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } static HRESULT GetItemBoolProp(IGetProp *getProp, PROPID propID, bool &result) { NCOM::CPropVariant prop; result = false; RINOK(getProp->GetProp(propID, &prop)); if (prop.vt == VT_BOOL) result = VARIANT_BOOLToBool(prop.boolVal); else if (prop.vt != VT_EMPTY) return E_FAIL; return S_OK; } STDMETHODIMP CExtractCallbackImp::GetStream7(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp) { COM_TRY_BEGIN *outStream = 0; _newVirtFileWasAdded = false; _hashStreamWasUsed = false; _needUpdateStat = false; if (_hashStream) _hashStreamSpec->ReleaseStream(); GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream); if (!ProcessAltStreams && _isAltStream) return S_OK; _filePath = name; _isFolder = IntToBool(isDir); _curSize = 0; _curSizeDefined = false; UInt64 size = 0; bool sizeDefined; { NCOM::CPropVariant prop; RINOK(getProp->GetProp(kpidSize, &prop)); sizeDefined = ConvertPropVariantToUInt64(prop, size); } if (sizeDefined) { _curSize = size; _curSizeDefined = true; } if (askExtractMode != NArchive::NExtract::NAskMode::kExtract && askExtractMode != NArchive::NExtract::NAskMode::kTest) return S_OK; _needUpdateStat = true; CMyComPtr outStreamLoc; if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract) { CVirtFile &file = VirtFileSystemSpec->AddNewFile(); _newVirtFileWasAdded = true; file.Name = name; file.IsDir = IntToBool(isDir); file.IsAltStream = _isAltStream; file.Size = 0; RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTimeDefined)); RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATimeDefined)); RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTimeDefined)); NCOM::CPropVariant prop; RINOK(getProp->GetProp(kpidAttrib, &prop)); if (prop.vt == VT_UI4) { file.Attrib = prop.ulVal; file.AttribDefined = true; } // else if (isDir) file.Attrib = FILE_ATTRIBUTE_DIRECTORY; file.ExpectedSize = 0; if (sizeDefined) file.ExpectedSize = size; outStreamLoc = VirtFileSystem; } if (_hashStream) { { _hashStreamSpec->SetStream(outStreamLoc); outStreamLoc = _hashStream; _hashStreamSpec->Init(true); _hashStreamWasUsed = true; } } if (outStreamLoc) *outStream = outStreamLoc.Detach(); return S_OK; COM_TRY_END } STDMETHODIMP CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode) { COM_TRY_BEGIN _needUpdateStat = ( askExtractMode == NArchive::NExtract::NAskMode::kExtract || askExtractMode == NArchive::NExtract::NAskMode::kTest); /* _extractMode = false; switch (askExtractMode) { case NArchive::NExtract::NAskMode::kExtract: if (_testMode) askExtractMode = NArchive::NExtract::NAskMode::kTest; else _extractMode = true; break; }; */ return SetCurrentFilePath2(_filePath); COM_TRY_END } STDMETHODIMP CExtractCallbackImp::SetOperationResult7(Int32 opRes, Int32 encrypted) { COM_TRY_BEGIN if (VirtFileSystem && _newVirtFileWasAdded) { // FIXME: probably we must request file size from VirtFileSystem // _curSize = VirtFileSystem->GetLastFileSize() // _curSizeDefined = true; RINOK(VirtFileSystemSpec->CloseMemFile()); } if (_hashStream && _hashStreamWasUsed) { _hashStreamSpec->_hash->Final(_isFolder, _isAltStream, _filePath); _curSize = _hashStreamSpec->GetSize(); _curSizeDefined = true; _hashStreamSpec->ReleaseStream(); _hashStreamWasUsed = false; } else if (_hashCalc && _needUpdateStat) { _hashCalc->SetSize(_curSize); _hashCalc->Final(_isFolder, _isAltStream, _filePath); } return SetOperationResult(opRes, encrypted); COM_TRY_END } static const size_t k_SizeT_MAX = (size_t)((size_t)0 - 1); static const UInt32 kBlockSize = ((UInt32)1 << 31); STDMETHODIMP CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize) *processedSize = 0; if (size == 0) return S_OK; if (!_fileMode) { CVirtFile &file = Files.Back(); size_t rem = file.Data.Size() - (size_t)file.Size; bool useMem = true; if (rem < size) { UInt64 b = 0; if (file.Data.Size() == 0) b = file.ExpectedSize; UInt64 a = file.Size + size; if (b < a) b = a; a = (UInt64)file.Data.Size() * 2; if (b < a) b = a; useMem = false; if (b <= k_SizeT_MAX && b <= MaxTotalAllocSize) useMem = file.Data.ReAlloc_KeepData((size_t)b, (size_t)file.Size); } if (useMem) { memcpy(file.Data + file.Size, data, size); file.Size += size; if (processedSize) *processedSize = (UInt32)size; return S_OK; } _fileMode = true; } RINOK(FlushToDisk(false)); return _outFileStream->Write(data, size, processedSize); } HRESULT CVirtFileSystem::FlushToDisk(bool closeLast) { if (!_outFileStream) { _outFileStreamSpec = new COutFileStream; _outFileStream = _outFileStreamSpec; } while (_numFlushed < Files.Size()) { const CVirtFile &file = Files[_numFlushed]; const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name)); if (!_fileIsOpen) { if (!_outFileStreamSpec->Create(path, false)) { _outFileStream.Release(); return E_FAIL; // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath)); } _fileIsOpen = true; RINOK(WriteStream(_outFileStream, file.Data, (size_t)file.Size)); } if (_numFlushed == Files.Size() - 1 && !closeLast) break; if (file.CTimeDefined || file.ATimeDefined || file.MTimeDefined) _outFileStreamSpec->SetTime( file.CTimeDefined ? &file.CTime : NULL, file.ATimeDefined ? &file.ATime : NULL, file.MTimeDefined ? &file.MTime : NULL); _outFileStreamSpec->Close(); _numFlushed++; _fileIsOpen = false; if (file.AttribDefined) NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib); } return S_OK; } #endif