X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=lzma%2FCPP%2F7zip%2FUI%2FCommon%2FArchiveExtractCallback.cpp;fp=lzma%2FCPP%2F7zip%2FUI%2FCommon%2FArchiveExtractCallback.cpp;h=c3913e1c7019450ff2ed3eb631590ea452541be5;hb=1a2e54b98aaab3669eebd38facb83687c4ac7baf;hp=0000000000000000000000000000000000000000;hpb=0b9bdac28929054558b5d7f315403fe3399a1413;p=physicsfs diff --git a/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp new file mode 100644 index 0000000..c3913e1 --- /dev/null +++ b/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp @@ -0,0 +1,479 @@ +// ArchiveExtractCallback.cpp + +#include "StdAfx.h" + +#include "ArchiveExtractCallback.h" + +#include "Common/Wildcard.h" +#include "Common/StringConvert.h" +#include "Common/ComTry.h" + +#include "Windows/FileDir.h" +#include "Windows/FileFind.h" +#include "Windows/Time.h" +#include "Windows/Defs.h" +#include "Windows/PropVariant.h" + +#include "Windows/PropVariantConversions.h" + +#include "../../Common/FilePathAutoRename.h" + +#include "../Common/ExtractingFilePath.h" +#include "OpenArchive.h" + +using namespace NWindows; + +static const wchar_t *kCantAutoRename = L"ERROR: Can not create file with auto name"; +static const wchar_t *kCantRenameFile = L"ERROR: Can not rename existing file "; +static const wchar_t *kCantDeleteOutputFile = L"ERROR: Can not delete output file "; + + +void CArchiveExtractCallback::Init( + IInArchive *archiveHandler, + IFolderArchiveExtractCallback *extractCallback2, + bool stdOutMode, + const UString &directoryPath, + const UStringVector &removePathParts, + const UString &itemDefaultName, + const FILETIME &utcLastWriteTimeDefault, + UInt32 attributesDefault, + UInt64 packSize) +{ + _stdOutMode = stdOutMode; + _numErrors = 0; + _unpTotal = 1; + _packTotal = packSize; + + _extractCallback2 = extractCallback2; + _compressProgress.Release(); + _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); + + LocalProgressSpec->Init(extractCallback2, true); + LocalProgressSpec->SendProgress = false; + + _itemDefaultName = itemDefaultName; + _utcLastWriteTimeDefault = utcLastWriteTimeDefault; + _attributesDefault = attributesDefault; + _removePathParts = removePathParts; + _archiveHandler = archiveHandler; + _directoryPath = directoryPath; + NFile::NName::NormalizeDirPathPrefix(_directoryPath); +} + +STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size) +{ + COM_TRY_BEGIN + _unpTotal = size; + if (!_multiArchives && _extractCallback2) + return _extractCallback2->SetTotal(size); + return S_OK; + COM_TRY_END +} + +static void NormalizeVals(UInt64 &v1, UInt64 &v2) +{ + const UInt64 kMax = (UInt64)1 << 31; + while (v1 > kMax) + { + v1 >>= 1; + v2 >>= 1; + } +} + +static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal) +{ + NormalizeVals(packTotal, unpTotal); + NormalizeVals(unpCur, unpTotal); + if (unpTotal == 0) + unpTotal = 1; + return unpCur * packTotal / unpTotal; +} + +STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue) +{ + COM_TRY_BEGIN + if (!_extractCallback2) + return S_OK; + + if (_multiArchives) + { + if (completeValue != NULL) + { + UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal); + return _extractCallback2->SetCompleted(&packCur); + } + } + return _extractCallback2->SetCompleted(completeValue); + COM_TRY_END +} + +STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + COM_TRY_BEGIN + return _localProgress->SetRatioInfo(inSize, outSize); + COM_TRY_END +} + +void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath) +{ + fullPath = _directoryPath; + for(int i = 0; i < dirPathParts.Size(); i++) + { + if (i > 0) + fullPath += wchar_t(NFile::NName::kDirDelimiter); + fullPath += dirPathParts[i]; + NFile::NDirectory::MyCreateDirectory(fullPath); + } +} + +static UString MakePathNameFromParts(const UStringVector &parts) +{ + UString result; + for(int i = 0; i < parts.Size(); i++) + { + if(i != 0) + result += wchar_t(NFile::NName::kDirDelimiter); + result += parts[i]; + } + return result; +} + + +HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) +{ + filetimeIsDefined = false; + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, propID, &prop)); + if (prop.vt == VT_FILETIME) + { + filetime = prop.filetime; + filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); + } + else if (prop.vt != VT_EMPTY) + return E_FAIL; + return S_OK; +} + +STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) +{ + COM_TRY_BEGIN + *outStream = 0; + _outFileStream.Release(); + + _encrypted = false; + _isSplit = false; + _curSize = 0; + + UString fullPath; + + RINOK(GetArchiveItemPath(_archiveHandler, index, _itemDefaultName, fullPath)); + RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.IsDirectory)); + + _filePath = fullPath; + + { + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, kpidPosition, &prop)); + if (prop.vt != VT_EMPTY) + { + if (prop.vt != VT_UI8) + return E_FAIL; + _position = prop.uhVal.QuadPart; + _isSplit = true; + } + } + + RINOK(IsArchiveItemProp(_archiveHandler, index, kpidEncrypted, _encrypted)); + + bool newFileSizeDefined; + UInt64 newFileSize; + { + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop)); + newFileSizeDefined = (prop.vt != VT_EMPTY); + if (newFileSizeDefined) + { + newFileSize = ConvertPropVariantToUInt64(prop); + _curSize = newFileSize; + } + } + + if(askExtractMode == NArchive::NExtract::NAskMode::kExtract) + { + if (_stdOutMode) + { + CMyComPtr outStreamLoc = new CStdOutFileStream; + *outStream = outStreamLoc.Detach(); + return S_OK; + } + + { + NCOM::CPropVariant prop; + RINOK(_archiveHandler->GetProperty(index, kpidAttributes, &prop)); + if (prop.vt == VT_EMPTY) + { + _processedFileInfo.Attributes = _attributesDefault; + _processedFileInfo.AttributesAreDefined = false; + } + else + { + if (prop.vt != VT_UI4) + return E_FAIL; + _processedFileInfo.Attributes = prop.ulVal; + _processedFileInfo.AttributesAreDefined = true; + } + } + + RINOK(GetTime(index, kpidCreationTime, _processedFileInfo.CreationTime, + _processedFileInfo.IsCreationTimeDefined)); + RINOK(GetTime(index, kpidLastWriteTime, _processedFileInfo.LastWriteTime, + _processedFileInfo.IsLastWriteTimeDefined)); + RINOK(GetTime(index, kpidLastAccessTime, _processedFileInfo.LastAccessTime, + _processedFileInfo.IsLastAccessTimeDefined)); + + bool isAnti = false; + RINOK(IsArchiveItemProp(_archiveHandler, index, kpidIsAnti, isAnti)); + + UStringVector pathParts; + SplitPathToParts(fullPath, pathParts); + + if(pathParts.IsEmpty()) + return E_FAIL; + int numRemovePathParts = 0; + switch(_pathMode) + { + case NExtract::NPathMode::kFullPathnames: + break; + case NExtract::NPathMode::kCurrentPathnames: + { + numRemovePathParts = _removePathParts.Size(); + if (pathParts.Size() <= numRemovePathParts) + return E_FAIL; + for (int i = 0; i < numRemovePathParts; i++) + if (_removePathParts[i].CompareNoCase(pathParts[i]) != 0) + return E_FAIL; + break; + } + case NExtract::NPathMode::kNoPathnames: + { + numRemovePathParts = pathParts.Size() - 1; + break; + } + } + pathParts.Delete(0, numRemovePathParts); + MakeCorrectPath(pathParts); + UString processedPath = MakePathNameFromParts(pathParts); + if (!isAnti) + { + if (!_processedFileInfo.IsDirectory) + { + if (!pathParts.IsEmpty()) + pathParts.DeleteBack(); + } + + if (!pathParts.IsEmpty()) + { + UString fullPathNew; + CreateComplexDirectory(pathParts, fullPathNew); + if (_processedFileInfo.IsDirectory) + NFile::NDirectory::SetDirTime(fullPathNew, + (WriteCreated && _processedFileInfo.IsCreationTimeDefined) ? &_processedFileInfo.CreationTime : NULL, + (WriteAccessed && _processedFileInfo.IsLastAccessTimeDefined) ? &_processedFileInfo.LastAccessTime : NULL, + (WriteModified && _processedFileInfo.IsLastWriteTimeDefined) ? &_processedFileInfo.LastWriteTime : &_utcLastWriteTimeDefault); + } + } + + + UString fullProcessedPath = _directoryPath + processedPath; + + if(_processedFileInfo.IsDirectory) + { + _diskFilePath = fullProcessedPath; + if (isAnti) + NFile::NDirectory::MyRemoveDirectory(_diskFilePath); + return S_OK; + } + + if (!_isSplit) + { + NFile::NFind::CFileInfoW fileInfo; + if(NFile::NFind::FindFile(fullProcessedPath, fileInfo)) + { + switch(_overwriteMode) + { + case NExtract::NOverwriteMode::kSkipExisting: + return S_OK; + case NExtract::NOverwriteMode::kAskBefore: + { + Int32 overwiteResult; + RINOK(_extractCallback2->AskOverwrite( + fullProcessedPath, &fileInfo.LastWriteTime, &fileInfo.Size, fullPath, + _processedFileInfo.IsLastWriteTimeDefined ? &_processedFileInfo.LastWriteTime : NULL, + newFileSizeDefined ? &newFileSize : NULL, + &overwiteResult)) + + switch(overwiteResult) + { + case NOverwriteAnswer::kCancel: + return E_ABORT; + case NOverwriteAnswer::kNo: + return S_OK; + case NOverwriteAnswer::kNoToAll: + _overwriteMode = NExtract::NOverwriteMode::kSkipExisting; + return S_OK; + case NOverwriteAnswer::kYesToAll: + _overwriteMode = NExtract::NOverwriteMode::kWithoutPrompt; + break; + case NOverwriteAnswer::kYes: + break; + case NOverwriteAnswer::kAutoRename: + _overwriteMode = NExtract::NOverwriteMode::kAutoRename; + break; + default: + return E_FAIL; + } + } + } + if (_overwriteMode == NExtract::NOverwriteMode::kAutoRename) + { + if (!AutoRenamePath(fullProcessedPath)) + { + UString message = UString(kCantAutoRename) + fullProcessedPath; + RINOK(_extractCallback2->MessageError(message)); + return E_FAIL; + } + } + else if (_overwriteMode == NExtract::NOverwriteMode::kAutoRenameExisting) + { + UString existPath = fullProcessedPath; + if (!AutoRenamePath(existPath)) + { + UString message = kCantAutoRename + fullProcessedPath; + RINOK(_extractCallback2->MessageError(message)); + return E_FAIL; + } + if(!NFile::NDirectory::MyMoveFile(fullProcessedPath, existPath)) + { + UString message = UString(kCantRenameFile) + fullProcessedPath; + RINOK(_extractCallback2->MessageError(message)); + return E_FAIL; + } + } + else + if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath)) + { + UString message = UString(kCantDeleteOutputFile) + fullProcessedPath; + RINOK(_extractCallback2->MessageError(message)); + return S_OK; + // return E_FAIL; + } + } + } + if (!isAnti) + { + _outFileStreamSpec = new COutFileStream; + CMyComPtr outStreamLoc(_outFileStreamSpec); + if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS)) + { + // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit) + { + UString message = L"can not open output file " + fullProcessedPath; + RINOK(_extractCallback2->MessageError(message)); + return S_OK; + } + } + if (_isSplit) + { + RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL)); + } + _outFileStream = outStreamLoc; + *outStream = outStreamLoc.Detach(); + } + _diskFilePath = fullProcessedPath; + } + else + { + *outStream = NULL; + } + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) +{ + COM_TRY_BEGIN + _extractMode = false; + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: + _extractMode = true; + }; + return _extractCallback2->PrepareOperation(_filePath, _processedFileInfo.IsDirectory, + askExtractMode, _isSplit ? &_position: 0); + COM_TRY_END +} + +STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult) +{ + COM_TRY_BEGIN + switch(operationResult) + { + case NArchive::NExtract::NOperationResult::kOK: + case NArchive::NExtract::NOperationResult::kUnSupportedMethod: + case NArchive::NExtract::NOperationResult::kCRCError: + case NArchive::NExtract::NOperationResult::kDataError: + break; + default: + _outFileStream.Release(); + return E_FAIL; + } + if (_outFileStream != NULL) + { + _outFileStreamSpec->SetTime( + (WriteCreated && _processedFileInfo.IsCreationTimeDefined) ? &_processedFileInfo.CreationTime : NULL, + (WriteAccessed && _processedFileInfo.IsLastAccessTimeDefined) ? &_processedFileInfo.LastAccessTime : NULL, + (WriteModified && _processedFileInfo.IsLastWriteTimeDefined) ? &_processedFileInfo.LastWriteTime : &_utcLastWriteTimeDefault); + _curSize = _outFileStreamSpec->ProcessedSize; + RINOK(_outFileStreamSpec->Close()); + _outFileStream.Release(); + } + UnpackSize += _curSize; + if (_processedFileInfo.IsDirectory) + NumFolders++; + else + NumFiles++; + + if (_extractMode && _processedFileInfo.AttributesAreDefined) + NFile::NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attributes); + RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted)); + return S_OK; + COM_TRY_END +} + +/* +STDMETHODIMP CArchiveExtractCallback::GetInStream( + const wchar_t *name, ISequentialInStream **inStream) +{ + COM_TRY_BEGIN + CInFileStream *inFile = new CInFileStream; + CMyComPtr inStreamTemp = inFile; + if (!inFile->Open(_srcDirectoryPrefix + name)) + return ::GetLastError(); + *inStream = inStreamTemp.Detach(); + return S_OK; + COM_TRY_END +} +*/ + +STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password) +{ + COM_TRY_BEGIN + if (!_cryptoGetTextPassword) + { + RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword, + &_cryptoGetTextPassword)); + } + return _cryptoGetTextPassword->CryptoGetTextPassword(password); + COM_TRY_END +} +