// 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 "ExtractCallback.h" | |
#include "FormatUtils.h" | |
#include "LangUtils.h" | |
#include "OverwriteDialog.h" | |
#ifndef _NO_CRYPTO | |
#include "PasswordDialog.h" | |
#endif | |
using namespace NWindows; | |
using namespace NFile; | |
using namespace NFind; | |
CExtractCallbackImp::~CExtractCallbackImp() {} | |
void CExtractCallbackImp::Init() | |
{ | |
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 * /* numFiles */, const UInt64 * /* numBytes */) | |
{ | |
// if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesTotal(*numFiles); | |
return S_OK; | |
} | |
HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */) | |
{ | |
// if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesCur(*numFiles); | |
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_ClearPasswordWasAskedFlag() | |
{ | |
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, bool isFolder, Int32 /* askExtractMode */, const UInt64 * /* position */) | |
{ | |
_isFolder = isFolder; | |
return SetCurrentFilePath2(name); | |
} | |
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 | |
STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 opRes, bool encrypted) | |
{ | |
switch (opRes) | |
{ | |
case NArchive::NExtract::NOperationResult::kOK: | |
break; | |
default: | |
{ | |
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; | |
/* | |
default: | |
messageID = IDS_EXTRACT_MESSAGE_UNKNOWN_ERROR; | |
break; | |
*/ | |
} | |
if (_needWriteArchivePath) | |
{ | |
if (!_currentArchivePath.IsEmpty()) | |
AddError_Message(_currentArchivePath); | |
_needWriteArchivePath = false; | |
} | |
UString msg; | |
UString msgOld; | |
#ifndef _SFX | |
if (id != 0) | |
LangString_OnlyFromLangFile(id, msg); | |
if (messageID != 0 && msg.IsEmpty()) | |
LangString_OnlyFromLangFile(messageID, msgOld); | |
#endif | |
UString s; | |
if (msg.IsEmpty() && !msgOld.IsEmpty()) | |
s = MyFormatNew(msgOld, _currentFilePath); | |
else | |
{ | |
if (msg.IsEmpty()) | |
LangString(id, msg); | |
if (!msg.IsEmpty()) | |
s += msg; | |
else | |
{ | |
wchar_t temp[16]; | |
ConvertUInt32ToString(opRes, temp); | |
s += L"Error #"; | |
s += temp; | |
} | |
if (encrypted) | |
{ | |
// s += L" : "; | |
// s += LangString(IDS_EXTRACT_MSG_ENCRYPTED); | |
s += L" : "; | |
s += LangString(IDS_EXTRACT_MSG_WRONG_PSW); | |
} | |
s += L" : "; | |
s += _currentFilePath; | |
} | |
AddError_Message(s); | |
} | |
} | |
#ifndef _SFX | |
if (_isFolder) | |
NumFolders++; | |
else | |
NumFiles++; | |
ProgressDialog->Sync.Set_NumFilesCur(NumFiles); | |
#endif | |
return S_OK; | |
} | |
//////////////////////////////////////// | |
// IExtractCallbackUI | |
HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name) | |
{ | |
#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); | |
HRESULT CExtractCallbackImp::OpenResult(const wchar_t *name, HRESULT result, bool encrypted) | |
{ | |
if (result != S_OK) | |
{ | |
UString s; | |
if (result == S_FALSE) | |
s = MyFormatNew(encrypted ? IDS_CANT_OPEN_ENCRYPTED_ARCHIVE : IDS_CANT_OPEN_ARCHIVE, name); | |
else | |
{ | |
s = name; | |
s += L": "; | |
s += HResultToMessage(result); | |
} | |
MessageError(s); | |
NumArchiveErrors++; | |
} | |
_currentArchivePath = name; | |
_needWriteArchivePath = true; | |
return S_OK; | |
} | |
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 | |
}; | |
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 += L" : "; | |
m += LangString(IDS_EXTRACT_MSG_WRONG_PSW); | |
} | |
if (!s.IsEmpty()) | |
s += L'\n'; | |
s += m; | |
errorFlags &= ~f; | |
} | |
if (errorFlags != 0) | |
{ | |
char sz[16]; | |
sz[0] = '0'; | |
sz[1] = 'x'; | |
ConvertUInt32ToHex(errorFlags, sz + 2); | |
if (!s.IsEmpty()) | |
s += L'\n'; | |
s += GetUnicodeString(AString(sz)); | |
} | |
return s; | |
} | |
HRESULT CExtractCallbackImp::SetError(int level, const wchar_t *name, | |
UInt32 errorFlags, const wchar_t *errors, | |
UInt32 warningFlags, const wchar_t *warnings) | |
{ | |
NumArchiveErrors++; | |
if (_needWriteArchivePath) | |
{ | |
if (!_currentArchivePath.IsEmpty()) | |
AddError_Message(_currentArchivePath); | |
_needWriteArchivePath = false; | |
} | |
if (level != 0) | |
{ | |
UString s; | |
s += name; | |
s += L": "; | |
MessageError(s); | |
} | |
if (errorFlags != 0) | |
MessageError(GetOpenArcErrorMessage(errorFlags)); | |
if (errors && wcslen(errors) != 0) | |
MessageError(errors); | |
if (warningFlags != 0) | |
MessageError((UString)L"Warnings: " + GetOpenArcErrorMessage(warningFlags)); | |
if (warnings && wcslen(warnings) != 0) | |
MessageError((UString)L"Warnings: " + warnings); | |
return S_OK; | |
} | |
HRESULT CExtractCallbackImp::OpenTypeWarning(const wchar_t *name, const wchar_t *okType, const wchar_t *errorType) | |
{ | |
UString s = L"Warning:\n"; | |
s += name; | |
s += L"\n"; | |
if (wcscmp(okType, errorType) == 0) | |
{ | |
s += L"The archive is open with offset"; | |
} | |
else | |
{ | |
s += L"Can not open the file as ["; | |
s += errorType; | |
s += L"] archive\n"; | |
s += L"The file is open as ["; | |
s += okType; | |
s += L"] archive"; | |
} | |
MessageError(s); | |
NumArchiveErrors++; | |
return S_OK; | |
} | |
HRESULT CExtractCallbackImp::ThereAreNoFiles() | |
{ | |
return S_OK; | |
} | |
HRESULT CExtractCallbackImp::ExtractResult(HRESULT result) | |
{ | |
if (result == S_OK) | |
return result; | |
NumArchiveErrors++; | |
if (result == E_ABORT || result == ERROR_DISK_FULL) | |
return result; | |
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)); | |
return E_FAIL; | |
} | |
switch (OverwriteMode) | |
{ | |
case NExtract::NOverwriteMode::kSkip: | |
return S_OK; | |
case NExtract::NOverwriteMode::kAsk: | |
{ | |
Int32 overwiteResult; | |
UString destPathSpec = destPath; | |
int slashPos = destPathSpec.ReverseFind(L'/'); | |
#ifdef _WIN32 | |
int slash1Pos = destPathSpec.ReverseFind(L'\\'); | |
slashPos = MyMax(slashPos, slash1Pos); | |
#endif | |
destPathSpec.DeleteFrom(slashPos + 1); | |
destPathSpec += fs2us(destFileInfo.Name); | |
RINOK(AskOverwrite( | |
destPathSpec, | |
&destFileInfo.MTime, &destFileInfo.Size, | |
srcPath, | |
srcTime, srcSize, | |
&overwiteResult)); | |
switch (overwiteResult) | |
{ | |
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<ISequentialOutStream> 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, bool 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(GetCorrectFsPath(file.Name)); | |
if (!_fileIsOpen) | |
{ | |
if (!_outFileStreamSpec->Create(path, false)) | |
{ | |
_outFileStream.Release(); | |
return E_FAIL; | |
// MessageBoxMyError(UString(L"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(path, file.Attrib); | |
} | |
return S_OK; | |
} | |
#endif |