mirror of
https://github.com/love2d/megasource.git
synced 2026-08-20 20:50:52 +02:00
Add PhysFS 2.0.3.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,104 @@
|
||||
// ArchiveCommandLine.h
|
||||
|
||||
#ifndef __ARCHIVECOMMANDLINE_H
|
||||
#define __ARCHIVECOMMANDLINE_H
|
||||
|
||||
#include "Common/Wildcard.h"
|
||||
#include "Common/CommandLineParser.h"
|
||||
|
||||
#include "Extract.h"
|
||||
#include "Update.h"
|
||||
|
||||
struct CArchiveCommandLineException: public AString
|
||||
{
|
||||
CArchiveCommandLineException(const char *errorMessage): AString(errorMessage) {}
|
||||
};
|
||||
|
||||
namespace NCommandType { enum EEnum
|
||||
{
|
||||
kAdd = 0,
|
||||
kUpdate,
|
||||
kDelete,
|
||||
kTest,
|
||||
kExtract,
|
||||
kFullExtract,
|
||||
kList,
|
||||
kBenchmark,
|
||||
kInfo
|
||||
};}
|
||||
|
||||
namespace NRecursedType { enum EEnum
|
||||
{
|
||||
kRecursed,
|
||||
kWildCardOnlyRecursed,
|
||||
kNonRecursed
|
||||
};}
|
||||
|
||||
struct CArchiveCommand
|
||||
{
|
||||
NCommandType::EEnum CommandType;
|
||||
bool IsFromExtractGroup() const;
|
||||
bool IsFromUpdateGroup() const;
|
||||
bool IsTestMode() const { return CommandType == NCommandType::kTest; }
|
||||
NExtract::NPathMode::EEnum GetPathMode() const;
|
||||
};
|
||||
|
||||
struct CArchiveCommandLineOptions
|
||||
{
|
||||
bool HelpMode;
|
||||
|
||||
#ifdef _WIN32
|
||||
bool LargePages;
|
||||
#endif
|
||||
|
||||
bool IsInTerminal;
|
||||
bool IsStdOutTerminal;
|
||||
bool IsStdErrTerminal;
|
||||
bool StdInMode;
|
||||
bool StdOutMode;
|
||||
bool EnableHeaders;
|
||||
|
||||
bool YesToAll;
|
||||
bool ShowDialog;
|
||||
// NWildcard::CCensor ArchiveWildcardCensor;
|
||||
NWildcard::CCensor WildcardCensor;
|
||||
|
||||
CArchiveCommand Command;
|
||||
UString ArchiveName;
|
||||
|
||||
bool PasswordEnabled;
|
||||
UString Password;
|
||||
|
||||
bool TechMode;
|
||||
// Extract
|
||||
bool AppendName;
|
||||
UString OutputDir;
|
||||
NExtract::NOverwriteMode::EEnum OverwriteMode;
|
||||
UStringVector ArchivePathsSorted;
|
||||
UStringVector ArchivePathsFullSorted;
|
||||
CObjectVector<CProperty> ExtractProperties;
|
||||
|
||||
CUpdateOptions UpdateOptions;
|
||||
UString ArcType;
|
||||
bool EnablePercents;
|
||||
|
||||
// Benchmark
|
||||
UInt32 NumIterations;
|
||||
UInt32 NumThreads;
|
||||
UInt32 DictionarySize;
|
||||
UString Method;
|
||||
|
||||
|
||||
CArchiveCommandLineOptions(): StdInMode(false), StdOutMode(false) {};
|
||||
};
|
||||
|
||||
class CArchiveCommandLineParser
|
||||
{
|
||||
NCommandLineParser::CParser parser;
|
||||
public:
|
||||
CArchiveCommandLineParser();
|
||||
void Parse1(const UStringVector &commandStrings, CArchiveCommandLineOptions &options);
|
||||
void Parse2(CArchiveCommandLineOptions &options);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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<ISequentialOutStream> 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<ISequentialOutStream> 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<ISequentialInStream> 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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
// ArchiveExtractCallback.h
|
||||
|
||||
#ifndef __ARCHIVEEXTRACTCALLBACK_H
|
||||
#define __ARCHIVEEXTRACTCALLBACK_H
|
||||
|
||||
#include "../../Archive/IArchive.h"
|
||||
#include "IFileExtractCallback.h"
|
||||
|
||||
#include "Common/MyString.h"
|
||||
#include "Common/MyCom.h"
|
||||
|
||||
#include "../../Common/FileStreams.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
#include "../../IPassword.h"
|
||||
|
||||
#include "ExtractMode.h"
|
||||
|
||||
class CArchiveExtractCallback:
|
||||
public IArchiveExtractCallback,
|
||||
// public IArchiveVolumeExtractCallback,
|
||||
public ICryptoGetTextPassword,
|
||||
public ICompressProgressInfo,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP2(ICryptoGetTextPassword, ICompressProgressInfo)
|
||||
// COM_INTERFACE_ENTRY(IArchiveVolumeExtractCallback)
|
||||
|
||||
// IProgress
|
||||
STDMETHOD(SetTotal)(UInt64 size);
|
||||
STDMETHOD(SetCompleted)(const UInt64 *completeValue);
|
||||
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
|
||||
|
||||
// IExtractCallBack
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode);
|
||||
STDMETHOD(PrepareOperation)(Int32 askExtractMode);
|
||||
STDMETHOD(SetOperationResult)(Int32 resultEOperationResult);
|
||||
|
||||
// IArchiveVolumeExtractCallback
|
||||
// STDMETHOD(GetInStream)(const wchar_t *name, ISequentialInStream **inStream);
|
||||
|
||||
// ICryptoGetTextPassword
|
||||
STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword);
|
||||
|
||||
private:
|
||||
CMyComPtr<IInArchive> _archiveHandler;
|
||||
CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
|
||||
CMyComPtr<ICompressProgressInfo> _compressProgress;
|
||||
CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
|
||||
UString _directoryPath;
|
||||
NExtract::NPathMode::EEnum _pathMode;
|
||||
NExtract::NOverwriteMode::EEnum _overwriteMode;
|
||||
|
||||
UString _filePath;
|
||||
UInt64 _position;
|
||||
bool _isSplit;
|
||||
|
||||
UString _diskFilePath;
|
||||
|
||||
bool _extractMode;
|
||||
|
||||
bool WriteModified;
|
||||
bool WriteCreated;
|
||||
bool WriteAccessed;
|
||||
|
||||
bool _encrypted;
|
||||
|
||||
struct CProcessedFileInfo
|
||||
{
|
||||
FILETIME CreationTime;
|
||||
FILETIME LastWriteTime;
|
||||
FILETIME LastAccessTime;
|
||||
UInt32 Attributes;
|
||||
|
||||
bool IsCreationTimeDefined;
|
||||
bool IsLastWriteTimeDefined;
|
||||
bool IsLastAccessTimeDefined;
|
||||
|
||||
bool IsDirectory;
|
||||
bool AttributesAreDefined;
|
||||
} _processedFileInfo;
|
||||
|
||||
UInt64 _curSize;
|
||||
COutFileStream *_outFileStreamSpec;
|
||||
CMyComPtr<ISequentialOutStream> _outFileStream;
|
||||
UStringVector _removePathParts;
|
||||
|
||||
UString _itemDefaultName;
|
||||
FILETIME _utcLastWriteTimeDefault;
|
||||
UInt32 _attributesDefault;
|
||||
bool _stdOutMode;
|
||||
|
||||
void CreateComplexDirectory(const UStringVector &dirPathParts, UString &fullPath);
|
||||
HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
|
||||
public:
|
||||
CArchiveExtractCallback():
|
||||
WriteModified(true),
|
||||
WriteCreated(false),
|
||||
WriteAccessed(false),
|
||||
_multiArchives(false)
|
||||
{
|
||||
LocalProgressSpec = new CLocalProgress();
|
||||
_localProgress = LocalProgressSpec;
|
||||
}
|
||||
|
||||
CLocalProgress *LocalProgressSpec;
|
||||
CMyComPtr<ICompressProgressInfo> _localProgress;
|
||||
UInt64 _packTotal;
|
||||
UInt64 _unpTotal;
|
||||
|
||||
bool _multiArchives;
|
||||
UInt64 NumFolders;
|
||||
UInt64 NumFiles;
|
||||
UInt64 UnpackSize;
|
||||
|
||||
void InitForMulti(bool multiArchives,
|
||||
NExtract::NPathMode::EEnum pathMode,
|
||||
NExtract::NOverwriteMode::EEnum overwriteMode)
|
||||
{
|
||||
_multiArchives = multiArchives; NumFolders = NumFiles = UnpackSize = 0;
|
||||
_pathMode = pathMode;
|
||||
_overwriteMode = overwriteMode;
|
||||
}
|
||||
|
||||
void Init(
|
||||
IInArchive *archiveHandler,
|
||||
IFolderArchiveExtractCallback *extractCallback2,
|
||||
bool stdOutMode,
|
||||
const UString &directoryPath,
|
||||
const UStringVector &removePathParts,
|
||||
const UString &itemDefaultName,
|
||||
const FILETIME &utcLastWriteTimeDefault,
|
||||
UInt32 attributesDefault,
|
||||
UInt64 packSize);
|
||||
|
||||
UInt64 _numErrors;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
// ArchiveName.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Windows/FileFind.h"
|
||||
#include "Windows/FileDir.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName)
|
||||
{
|
||||
UString resultName = L"Archive";
|
||||
if (fromPrev)
|
||||
{
|
||||
UString dirPrefix;
|
||||
if (NFile::NDirectory::GetOnlyDirPrefix(srcName, dirPrefix))
|
||||
{
|
||||
if (dirPrefix.Length() > 0)
|
||||
if (dirPrefix[dirPrefix.Length() - 1] == '\\')
|
||||
{
|
||||
dirPrefix.Delete(dirPrefix.Length() - 1);
|
||||
NFile::NFind::CFileInfoW fileInfo;
|
||||
if (NFile::NFind::FindFile(dirPrefix, fileInfo))
|
||||
resultName = fileInfo.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NFile::NFind::CFileInfoW fileInfo;
|
||||
if (!NFile::NFind::FindFile(srcName, fileInfo))
|
||||
return resultName;
|
||||
resultName = fileInfo.Name;
|
||||
if (!fileInfo.IsDirectory() && !keepName)
|
||||
{
|
||||
int dotPos = resultName.ReverseFind('.');
|
||||
if (dotPos > 0)
|
||||
{
|
||||
UString archiveName2 = resultName.Left(dotPos);
|
||||
if (archiveName2.ReverseFind('.') < 0)
|
||||
resultName = archiveName2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultName;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// ArchiveName.h
|
||||
|
||||
#ifndef __ARCHIVENAME_H
|
||||
#define __ARCHIVENAME_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
|
||||
UString CreateArchiveName(const UString &srcName, bool fromPrev, bool keepName);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,137 @@
|
||||
// ArchiveOpenCallback.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "ArchiveOpenCallback.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/ComTry.h"
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../Common/FileStreams.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if (!Callback)
|
||||
return S_OK;
|
||||
return Callback->SetTotal(files, bytes);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if (!Callback)
|
||||
return S_OK;
|
||||
return Callback->SetTotal(files, bytes);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NCOM::CPropVariant propVariant;
|
||||
if (_subArchiveMode)
|
||||
{
|
||||
switch(propID)
|
||||
{
|
||||
case kpidName:
|
||||
propVariant = _subArchiveName;
|
||||
break;
|
||||
}
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
switch(propID)
|
||||
{
|
||||
case kpidName:
|
||||
propVariant = _fileInfo.Name;
|
||||
break;
|
||||
case kpidIsFolder:
|
||||
propVariant = _fileInfo.IsDirectory();
|
||||
break;
|
||||
case kpidSize:
|
||||
propVariant = _fileInfo.Size;
|
||||
break;
|
||||
case kpidAttributes:
|
||||
propVariant = (UInt32)_fileInfo.Attributes;
|
||||
break;
|
||||
case kpidLastAccessTime:
|
||||
propVariant = _fileInfo.LastAccessTime;
|
||||
break;
|
||||
case kpidCreationTime:
|
||||
propVariant = _fileInfo.CreationTime;
|
||||
break;
|
||||
case kpidLastWriteTime:
|
||||
propVariant = _fileInfo.LastWriteTime;
|
||||
break;
|
||||
}
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
int COpenCallbackImp::FindName(const UString &name)
|
||||
{
|
||||
for (int i = 0; i < FileNames.Size(); i++)
|
||||
if (name.CompareNoCase(FileNames[i]) == 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct CInFileStreamVol: public CInFileStream
|
||||
{
|
||||
UString Name;
|
||||
COpenCallbackImp *OpenCallbackImp;
|
||||
CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
|
||||
~CInFileStreamVol()
|
||||
{
|
||||
int index = OpenCallbackImp->FindName(Name);
|
||||
if (index >= 0)
|
||||
OpenCallbackImp->FileNames.Delete(index);
|
||||
}
|
||||
};
|
||||
|
||||
STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if (_subArchiveMode)
|
||||
return S_FALSE;
|
||||
if (Callback)
|
||||
{
|
||||
RINOK(Callback->CheckBreak());
|
||||
}
|
||||
*inStream = NULL;
|
||||
UString fullPath = _folderPrefix + name;
|
||||
if (!NFile::NFind::FindFile(fullPath, _fileInfo))
|
||||
return S_FALSE;
|
||||
if (_fileInfo.IsDirectory())
|
||||
return S_FALSE;
|
||||
CInFileStreamVol *inFile = new CInFileStreamVol;
|
||||
CMyComPtr<IInStream> inStreamTemp = inFile;
|
||||
if (!inFile->Open(fullPath))
|
||||
return ::GetLastError();
|
||||
*inStream = inStreamTemp.Detach();
|
||||
inFile->Name = name;
|
||||
inFile->OpenCallbackImp = this;
|
||||
inFile->OpenCallbackRef = this;
|
||||
FileNames.Add(name);
|
||||
TotalSize += _fileInfo.Size;
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
if (!Callback)
|
||||
return E_NOTIMPL;
|
||||
return Callback->CryptoGetTextPassword(password);
|
||||
COM_TRY_END
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// ArchiveOpenCallback.h
|
||||
|
||||
#ifndef __ARCHIVE_OPEN_CALLBACK_H
|
||||
#define __ARCHIVE_OPEN_CALLBACK_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
#include "Common/MyCom.h"
|
||||
#include "Windows/FileFind.h"
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
#include "../../IPassword.h"
|
||||
#endif
|
||||
#include "../../Archive/IArchive.h"
|
||||
|
||||
struct IOpenCallbackUI
|
||||
{
|
||||
virtual HRESULT CheckBreak() = 0;
|
||||
virtual HRESULT SetTotal(const UInt64 *files, const UInt64 *bytes) = 0;
|
||||
virtual HRESULT SetCompleted(const UInt64 *files, const UInt64 *bytes) = 0;
|
||||
#ifndef _NO_CRYPTO
|
||||
virtual HRESULT CryptoGetTextPassword(BSTR *password) = 0;
|
||||
virtual HRESULT GetPasswordIfAny(UString &password) = 0;
|
||||
virtual bool WasPasswordAsked() = 0;
|
||||
virtual void ClearPasswordWasAskedFlag() = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
class COpenCallbackImp:
|
||||
public IArchiveOpenCallback,
|
||||
public IArchiveOpenVolumeCallback,
|
||||
public IArchiveOpenSetSubArchiveName,
|
||||
#ifndef _NO_CRYPTO
|
||||
public ICryptoGetTextPassword,
|
||||
#endif
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
#ifndef _NO_CRYPTO
|
||||
MY_UNKNOWN_IMP3(
|
||||
IArchiveOpenVolumeCallback,
|
||||
ICryptoGetTextPassword,
|
||||
IArchiveOpenSetSubArchiveName
|
||||
)
|
||||
#else
|
||||
MY_UNKNOWN_IMP2(
|
||||
IArchiveOpenVolumeCallback,
|
||||
IArchiveOpenSetSubArchiveName
|
||||
)
|
||||
#endif
|
||||
|
||||
STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);
|
||||
STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);
|
||||
|
||||
// IArchiveOpenVolumeCallback
|
||||
STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value);
|
||||
STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream);
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
// ICryptoGetTextPassword
|
||||
STDMETHOD(CryptoGetTextPassword)(BSTR *password);
|
||||
#endif
|
||||
|
||||
STDMETHOD(SetSubArchiveName(const wchar_t *name))
|
||||
{
|
||||
_subArchiveMode = true;
|
||||
_subArchiveName = name;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
UString _folderPrefix;
|
||||
NWindows::NFile::NFind::CFileInfoW _fileInfo;
|
||||
bool _subArchiveMode;
|
||||
UString _subArchiveName;
|
||||
public:
|
||||
UStringVector FileNames;
|
||||
IOpenCallbackUI *Callback;
|
||||
UInt64 TotalSize;
|
||||
|
||||
COpenCallbackImp(): Callback(NULL) {}
|
||||
void Init(const UString &folderPrefix, const UString &fileName)
|
||||
{
|
||||
_folderPrefix = folderPrefix;
|
||||
if (!NWindows::NFile::NFind::FindFile(_folderPrefix + fileName, _fileInfo))
|
||||
throw 1;
|
||||
FileNames.Clear();
|
||||
_subArchiveMode = false;
|
||||
TotalSize = 0;
|
||||
}
|
||||
int FindName(const UString &name);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
// DefaultName.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "DefaultName.h"
|
||||
|
||||
static const wchar_t *kEmptyFileAlias = L"[Content]";
|
||||
|
||||
UString GetDefaultName2(const UString &fileName,
|
||||
const UString &extension, const UString &addSubExtension)
|
||||
{
|
||||
int extLength = extension.Length();
|
||||
int fileNameLength = fileName.Length();
|
||||
if (fileNameLength > extLength + 1)
|
||||
{
|
||||
int dotPos = fileNameLength - (extLength + 1);
|
||||
if (fileName[dotPos] == '.')
|
||||
if (extension.CompareNoCase(fileName.Mid(dotPos + 1)) == 0)
|
||||
return fileName.Left(dotPos) + addSubExtension;
|
||||
}
|
||||
int dotPos = fileName.ReverseFind(L'.');
|
||||
if (dotPos > 0)
|
||||
return fileName.Left(dotPos) + addSubExtension;
|
||||
return kEmptyFileAlias;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// DefaultName.h
|
||||
|
||||
#ifndef __DEFAULTNAME_H
|
||||
#define __DEFAULTNAME_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
|
||||
UString GetDefaultName2(const UString &fileName,
|
||||
const UString &extension, const UString &addSubExtension);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
// DirItem.h
|
||||
|
||||
#ifndef __DIR_ITEM_H
|
||||
#define __DIR_ITEM_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
#include "Common/Types.h"
|
||||
|
||||
struct CDirItem
|
||||
{
|
||||
UInt32 Attributes;
|
||||
FILETIME CreationTime;
|
||||
FILETIME LastAccessTime;
|
||||
FILETIME LastWriteTime;
|
||||
UInt64 Size;
|
||||
UString Name;
|
||||
UString FullPath;
|
||||
bool IsDirectory() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
|
||||
};
|
||||
|
||||
struct CArchiveItem
|
||||
{
|
||||
bool IsDirectory;
|
||||
// DWORD Attributes;
|
||||
// NWindows::NCOM::CPropVariant LastWriteTime;
|
||||
FILETIME LastWriteTime;
|
||||
bool SizeIsDefined;
|
||||
UInt64 Size;
|
||||
UString Name;
|
||||
bool Censored;
|
||||
int IndexInServer;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,281 @@
|
||||
// EnumDirItems.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/Wildcard.h"
|
||||
#include "Common/MyCom.h"
|
||||
|
||||
#include "EnumDirItems.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NFile;
|
||||
using namespace NName;
|
||||
|
||||
void AddDirFileInfo(
|
||||
const UString &prefix, // prefix for logical path
|
||||
const UString &fullPathName, // path on disk: can be relative to some basePrefix
|
||||
const NFind::CFileInfoW &fileInfo,
|
||||
CObjectVector<CDirItem> &dirItems)
|
||||
{
|
||||
CDirItem item;
|
||||
item.Attributes = fileInfo.Attributes;
|
||||
item.Size = fileInfo.Size;
|
||||
item.CreationTime = fileInfo.CreationTime;
|
||||
item.LastAccessTime = fileInfo.LastAccessTime;
|
||||
item.LastWriteTime = fileInfo.LastWriteTime;
|
||||
item.Name = prefix + fileInfo.Name;
|
||||
item.FullPath = fullPathName;
|
||||
dirItems.Add(item);
|
||||
}
|
||||
|
||||
static void EnumerateDirectory(
|
||||
const UString &baseFolderPrefix, // base (disk) prefix for scanning
|
||||
const UString &directory, // additional disk prefix starting from baseFolderPrefix
|
||||
const UString &prefix, // logical prefix
|
||||
CObjectVector<CDirItem> &dirItems,
|
||||
UStringVector &errorPaths,
|
||||
CRecordVector<DWORD> &errorCodes)
|
||||
{
|
||||
NFind::CEnumeratorW enumerator(baseFolderPrefix + directory + wchar_t(kAnyStringWildcard));
|
||||
for (;;)
|
||||
{
|
||||
NFind::CFileInfoW fileInfo;
|
||||
bool found;
|
||||
if (!enumerator.Next(fileInfo, found))
|
||||
{
|
||||
errorCodes.Add(::GetLastError());
|
||||
errorPaths.Add(baseFolderPrefix + directory);
|
||||
return;
|
||||
}
|
||||
if (!found)
|
||||
break;
|
||||
AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, dirItems);
|
||||
if (fileInfo.IsDirectory())
|
||||
{
|
||||
EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter),
|
||||
prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems, errorPaths, errorCodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EnumerateDirItems(
|
||||
const UString &baseFolderPrefix, // base (disk) prefix for scanning
|
||||
const UStringVector &fileNames, // names relative to baseFolderPrefix
|
||||
const UString &archiveNamePrefix,
|
||||
CObjectVector<CDirItem> &dirItems,
|
||||
UStringVector &errorPaths,
|
||||
CRecordVector<DWORD> &errorCodes)
|
||||
{
|
||||
for(int i = 0; i < fileNames.Size(); i++)
|
||||
{
|
||||
const UString &fileName = fileNames[i];
|
||||
NFind::CFileInfoW fileInfo;
|
||||
if (!NFind::FindFile(baseFolderPrefix + fileName, fileInfo))
|
||||
{
|
||||
errorCodes.Add(::GetLastError());
|
||||
errorPaths.Add(baseFolderPrefix + fileName);
|
||||
continue;
|
||||
}
|
||||
AddDirFileInfo(archiveNamePrefix, fileName, fileInfo, dirItems);
|
||||
if (fileInfo.IsDirectory())
|
||||
{
|
||||
EnumerateDirectory(baseFolderPrefix, fileName + wchar_t(kDirDelimiter),
|
||||
archiveNamePrefix + fileInfo.Name + wchar_t(kDirDelimiter),
|
||||
dirItems, errorPaths, errorCodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT EnumerateDirItems(
|
||||
const NWildcard::CCensorNode &curNode,
|
||||
const UString &diskPrefix, // full disk path prefix
|
||||
const UString &archivePrefix, // prefix from root
|
||||
const UStringVector &addArchivePrefix, // prefix from curNode
|
||||
CObjectVector<CDirItem> &dirItems,
|
||||
bool enterToSubFolders,
|
||||
IEnumDirItemCallback *callback,
|
||||
UStringVector &errorPaths,
|
||||
CRecordVector<DWORD> &errorCodes)
|
||||
{
|
||||
if (!enterToSubFolders)
|
||||
if (curNode.NeedCheckSubDirs())
|
||||
enterToSubFolders = true;
|
||||
if (callback)
|
||||
RINOK(callback->CheckBreak());
|
||||
|
||||
// try direct_names case at first
|
||||
if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
|
||||
{
|
||||
// check that all names are direct
|
||||
int i;
|
||||
for (i = 0; i < curNode.IncludeItems.Size(); i++)
|
||||
{
|
||||
const NWildcard::CItem &item = curNode.IncludeItems[i];
|
||||
if (item.Recursive || item.PathParts.Size() != 1)
|
||||
break;
|
||||
const UString &name = item.PathParts.Front();
|
||||
if (name.IsEmpty() || DoesNameContainWildCard(name))
|
||||
break;
|
||||
}
|
||||
if (i == curNode.IncludeItems.Size())
|
||||
{
|
||||
// all names are direct (no wildcards)
|
||||
// so we don't need file_system's dir enumerator
|
||||
CRecordVector<bool> needEnterVector;
|
||||
for (i = 0; i < curNode.IncludeItems.Size(); i++)
|
||||
{
|
||||
const NWildcard::CItem &item = curNode.IncludeItems[i];
|
||||
const UString &name = item.PathParts.Front();
|
||||
const UString fullPath = diskPrefix + name;
|
||||
NFind::CFileInfoW fileInfo;
|
||||
if (!NFind::FindFile(fullPath, fileInfo))
|
||||
{
|
||||
errorCodes.Add(::GetLastError());
|
||||
errorPaths.Add(fullPath);
|
||||
continue;
|
||||
}
|
||||
bool isDir = fileInfo.IsDirectory();
|
||||
if (isDir && !item.ForDir || !isDir && !item.ForFile)
|
||||
{
|
||||
errorCodes.Add((DWORD)E_FAIL);
|
||||
errorPaths.Add(fullPath);
|
||||
continue;
|
||||
}
|
||||
const UString realName = fileInfo.Name;
|
||||
const UString realDiskPath = diskPrefix + realName;
|
||||
{
|
||||
UStringVector pathParts;
|
||||
pathParts.Add(fileInfo.Name);
|
||||
if (curNode.CheckPathToRoot(false, pathParts, !isDir))
|
||||
continue;
|
||||
}
|
||||
AddDirFileInfo(archivePrefix, realDiskPath, fileInfo, dirItems);
|
||||
if (!isDir)
|
||||
continue;
|
||||
|
||||
UStringVector addArchivePrefixNew;
|
||||
const NWildcard::CCensorNode *nextNode = 0;
|
||||
int index = curNode.FindSubNode(name);
|
||||
if (index >= 0)
|
||||
{
|
||||
for (int t = needEnterVector.Size(); t <= index; t++)
|
||||
needEnterVector.Add(true);
|
||||
needEnterVector[index] = false;
|
||||
nextNode = &curNode.SubNodes[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
nextNode = &curNode;
|
||||
addArchivePrefixNew.Add(name); // don't change it to realName. It's for shortnames support
|
||||
}
|
||||
RINOK(EnumerateDirItems(*nextNode,
|
||||
realDiskPath + wchar_t(kDirDelimiter),
|
||||
archivePrefix + realName + wchar_t(kDirDelimiter),
|
||||
addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
|
||||
}
|
||||
for (i = 0; i < curNode.SubNodes.Size(); i++)
|
||||
{
|
||||
if (i < needEnterVector.Size())
|
||||
if (!needEnterVector[i])
|
||||
continue;
|
||||
const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
|
||||
const UString fullPath = diskPrefix + nextNode.Name;
|
||||
NFind::CFileInfoW fileInfo;
|
||||
if (!NFind::FindFile(fullPath, fileInfo))
|
||||
{
|
||||
if (!nextNode.AreThereIncludeItems())
|
||||
continue;
|
||||
errorCodes.Add(::GetLastError());
|
||||
errorPaths.Add(fullPath);
|
||||
continue;
|
||||
}
|
||||
if (!fileInfo.IsDirectory())
|
||||
{
|
||||
errorCodes.Add((DWORD)E_FAIL);
|
||||
errorPaths.Add(fullPath);
|
||||
continue;
|
||||
}
|
||||
RINOK(EnumerateDirItems(nextNode,
|
||||
diskPrefix + fileInfo.Name + wchar_t(kDirDelimiter),
|
||||
archivePrefix + fileInfo.Name + wchar_t(kDirDelimiter),
|
||||
UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NFind::CEnumeratorW enumerator(diskPrefix + wchar_t(kAnyStringWildcard));
|
||||
for (;;)
|
||||
{
|
||||
NFind::CFileInfoW fileInfo;
|
||||
bool found;
|
||||
if (!enumerator.Next(fileInfo, found))
|
||||
{
|
||||
errorCodes.Add(::GetLastError());
|
||||
errorPaths.Add(diskPrefix);
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
break;
|
||||
|
||||
if (callback)
|
||||
RINOK(callback->CheckBreak());
|
||||
const UString &name = fileInfo.Name;
|
||||
bool enterToSubFolders2 = enterToSubFolders;
|
||||
UStringVector addArchivePrefixNew = addArchivePrefix;
|
||||
addArchivePrefixNew.Add(name);
|
||||
{
|
||||
UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
|
||||
if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fileInfo.IsDirectory()))
|
||||
continue;
|
||||
}
|
||||
if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fileInfo.IsDirectory()))
|
||||
{
|
||||
AddDirFileInfo(archivePrefix, diskPrefix + name, fileInfo, dirItems);
|
||||
if (fileInfo.IsDirectory())
|
||||
enterToSubFolders2 = true;
|
||||
}
|
||||
if (!fileInfo.IsDirectory())
|
||||
continue;
|
||||
|
||||
const NWildcard::CCensorNode *nextNode = 0;
|
||||
if (addArchivePrefix.IsEmpty())
|
||||
{
|
||||
int index = curNode.FindSubNode(name);
|
||||
if (index >= 0)
|
||||
nextNode = &curNode.SubNodes[index];
|
||||
}
|
||||
if (!enterToSubFolders2 && nextNode == 0)
|
||||
continue;
|
||||
|
||||
addArchivePrefixNew = addArchivePrefix;
|
||||
if (nextNode == 0)
|
||||
{
|
||||
nextNode = &curNode;
|
||||
addArchivePrefixNew.Add(name);
|
||||
}
|
||||
RINOK(EnumerateDirItems(*nextNode,
|
||||
diskPrefix + name + wchar_t(kDirDelimiter),
|
||||
archivePrefix + name + wchar_t(kDirDelimiter),
|
||||
addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT EnumerateItems(
|
||||
const NWildcard::CCensor &censor,
|
||||
CObjectVector<CDirItem> &dirItems,
|
||||
IEnumDirItemCallback *callback,
|
||||
UStringVector &errorPaths,
|
||||
CRecordVector<DWORD> &errorCodes)
|
||||
{
|
||||
for (int i = 0; i < censor.Pairs.Size(); i++)
|
||||
{
|
||||
const NWildcard::CPair &pair = censor.Pairs[i];
|
||||
RINOK(EnumerateDirItems(pair.Head, pair.Prefix, L"", UStringVector(), dirItems, false,
|
||||
callback, errorPaths, errorCodes));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// EnumDirItems.h
|
||||
|
||||
#ifndef __ENUM_DIR_ITEMS_H
|
||||
#define __ENUM_DIR_ITEMS_H
|
||||
|
||||
#include "Common/Wildcard.h"
|
||||
#include "DirItem.h"
|
||||
|
||||
#include "Windows/FileFind.h"
|
||||
|
||||
void AddDirFileInfo(
|
||||
const UString &prefix,
|
||||
const UString &fullPathName,
|
||||
const NWindows::NFile::NFind::CFileInfoW &fileInfo,
|
||||
CObjectVector<CDirItem> &dirItems);
|
||||
|
||||
|
||||
void EnumerateDirItems(
|
||||
const UString &baseFolderPrefix,
|
||||
const UStringVector &fileNames,
|
||||
const UString &archiveNamePrefix,
|
||||
CObjectVector<CDirItem> &dirItems,
|
||||
UStringVector &errorPaths,
|
||||
CRecordVector<DWORD> &errorCodes);
|
||||
|
||||
struct IEnumDirItemCallback
|
||||
{
|
||||
virtual HRESULT CheckBreak() { return S_OK; }
|
||||
};
|
||||
|
||||
|
||||
HRESULT EnumerateItems(
|
||||
const NWildcard::CCensor &censor,
|
||||
CObjectVector<CDirItem> &dirItems,
|
||||
IEnumDirItemCallback *callback,
|
||||
UStringVector &errorPaths,
|
||||
CRecordVector<DWORD> &errorCodes);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
// ExitCode.h
|
||||
|
||||
#ifndef __EXIT_CODE_H
|
||||
#define __EXIT_CODE_H
|
||||
|
||||
namespace NExitCode {
|
||||
|
||||
enum EEnum {
|
||||
|
||||
kSuccess = 0, // Successful operation
|
||||
kWarning = 1, // Non fatal error(s) occurred
|
||||
kFatalError = 2, // A fatal error occurred
|
||||
// kCRCError = 3, // A CRC error occurred when unpacking
|
||||
// kLockedArchive = 4, // Attempt to modify an archive previously locked
|
||||
// kWriteError = 5, // Write to disk error
|
||||
// kOpenError = 6, // Open file error
|
||||
kUserError = 7, // Command line option error
|
||||
kMemoryError = 8, // Not enough memory for operation
|
||||
// kCreateFileError = 9, // Create file error
|
||||
|
||||
kUserBreak = 255 // User stopped the process
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,187 @@
|
||||
// Extract.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Extract.h"
|
||||
|
||||
#include "Windows/Defs.h"
|
||||
#include "Windows/FileDir.h"
|
||||
|
||||
#include "OpenArchive.h"
|
||||
#include "SetProperties.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
HRESULT DecompressArchive(
|
||||
IInArchive *archive,
|
||||
UInt64 packSize,
|
||||
const UString &defaultName,
|
||||
const NWildcard::CCensorNode &wildcardCensor,
|
||||
const CExtractOptions &options,
|
||||
IExtractCallbackUI *callback,
|
||||
CArchiveExtractCallback *extractCallbackSpec,
|
||||
UString &errorMessage)
|
||||
{
|
||||
CRecordVector<UInt32> realIndices;
|
||||
UInt32 numItems;
|
||||
RINOK(archive->GetNumberOfItems(&numItems));
|
||||
|
||||
for(UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
UString filePath;
|
||||
RINOK(GetArchiveItemPath(archive, i, options.DefaultItemName, filePath));
|
||||
bool isFolder;
|
||||
RINOK(IsArchiveItemFolder(archive, i, isFolder));
|
||||
if (!wildcardCensor.CheckPath(filePath, !isFolder))
|
||||
continue;
|
||||
realIndices.Add(i);
|
||||
}
|
||||
if (realIndices.Size() == 0)
|
||||
{
|
||||
callback->ThereAreNoFiles();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
UStringVector removePathParts;
|
||||
|
||||
UString outDir = options.OutputDir;
|
||||
outDir.Replace(L"*", defaultName);
|
||||
if(!outDir.IsEmpty())
|
||||
if(!NFile::NDirectory::CreateComplexDirectory(outDir))
|
||||
{
|
||||
HRESULT res = ::GetLastError();
|
||||
if (res == S_OK)
|
||||
res = E_FAIL;
|
||||
errorMessage = ((UString)L"Can not create output directory ") + outDir;
|
||||
return res;
|
||||
}
|
||||
|
||||
extractCallbackSpec->Init(
|
||||
archive,
|
||||
callback,
|
||||
options.StdOutMode,
|
||||
outDir,
|
||||
removePathParts,
|
||||
options.DefaultItemName,
|
||||
options.ArchiveFileInfo.LastWriteTime,
|
||||
options.ArchiveFileInfo.Attributes,
|
||||
packSize);
|
||||
|
||||
#ifdef COMPRESS_MT
|
||||
RINOK(SetProperties(archive, options.Properties));
|
||||
#endif
|
||||
|
||||
HRESULT result = archive->Extract(&realIndices.Front(),
|
||||
realIndices.Size(), options.TestMode? 1: 0, extractCallbackSpec);
|
||||
|
||||
return callback->ExtractResult(result);
|
||||
}
|
||||
|
||||
HRESULT DecompressArchives(
|
||||
CCodecs *codecs,
|
||||
UStringVector &archivePaths, UStringVector &archivePathsFull,
|
||||
const NWildcard::CCensorNode &wildcardCensor,
|
||||
const CExtractOptions &optionsSpec,
|
||||
IOpenCallbackUI *openCallback,
|
||||
IExtractCallbackUI *extractCallback,
|
||||
UString &errorMessage,
|
||||
CDecompressStat &stat)
|
||||
{
|
||||
stat.Clear();
|
||||
CExtractOptions options = optionsSpec;
|
||||
int i;
|
||||
UInt64 totalPackSize = 0;
|
||||
CRecordVector<UInt64> archiveSizes;
|
||||
for (i = 0; i < archivePaths.Size(); i++)
|
||||
{
|
||||
const UString &archivePath = archivePaths[i];
|
||||
NFile::NFind::CFileInfoW archiveFileInfo;
|
||||
if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
|
||||
throw "there is no such archive";
|
||||
if (archiveFileInfo.IsDirectory())
|
||||
throw "can't decompress folder";
|
||||
archiveSizes.Add(archiveFileInfo.Size);
|
||||
totalPackSize += archiveFileInfo.Size;
|
||||
}
|
||||
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
|
||||
CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec);
|
||||
bool multi = (archivePaths.Size() > 1);
|
||||
extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode);
|
||||
if (multi)
|
||||
{
|
||||
RINOK(extractCallback->SetTotal(totalPackSize));
|
||||
}
|
||||
for (i = 0; i < archivePaths.Size(); i++)
|
||||
{
|
||||
const UString &archivePath = archivePaths[i];
|
||||
NFile::NFind::CFileInfoW archiveFileInfo;
|
||||
if (!NFile::NFind::FindFile(archivePath, archiveFileInfo))
|
||||
throw "there is no such archive";
|
||||
|
||||
if (archiveFileInfo.IsDirectory())
|
||||
throw "there is no such archive";
|
||||
|
||||
options.ArchiveFileInfo = archiveFileInfo;
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
openCallback->ClearPasswordWasAskedFlag();
|
||||
#endif
|
||||
|
||||
RINOK(extractCallback->BeforeOpen(archivePath));
|
||||
CArchiveLink archiveLink;
|
||||
HRESULT result = MyOpenArchive(codecs, archivePath, archiveLink, openCallback);
|
||||
|
||||
bool crypted = false;
|
||||
#ifndef _NO_CRYPTO
|
||||
crypted = openCallback->WasPasswordAsked();
|
||||
#endif
|
||||
|
||||
RINOK(extractCallback->OpenResult(archivePath, result, crypted));
|
||||
if (result != S_OK)
|
||||
continue;
|
||||
|
||||
for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
|
||||
{
|
||||
int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]);
|
||||
if (index >= 0 && index > i)
|
||||
{
|
||||
archivePaths.Delete(index);
|
||||
archivePathsFull.Delete(index);
|
||||
totalPackSize -= archiveSizes[index];
|
||||
archiveSizes.Delete(index);
|
||||
}
|
||||
}
|
||||
if (archiveLink.VolumePaths.Size() != 0)
|
||||
{
|
||||
totalPackSize += archiveLink.VolumesSize;
|
||||
RINOK(extractCallback->SetTotal(totalPackSize));
|
||||
}
|
||||
|
||||
#ifndef _NO_CRYPTO
|
||||
UString password;
|
||||
RINOK(openCallback->GetPasswordIfAny(password));
|
||||
if (!password.IsEmpty())
|
||||
{
|
||||
RINOK(extractCallback->SetPassword(password));
|
||||
}
|
||||
#endif
|
||||
|
||||
options.DefaultItemName = archiveLink.GetDefaultItemName();
|
||||
RINOK(DecompressArchive(
|
||||
archiveLink.GetArchive(),
|
||||
archiveFileInfo.Size + archiveLink.VolumesSize,
|
||||
archiveLink.GetDefaultItemName(),
|
||||
wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage));
|
||||
extractCallbackSpec->LocalProgressSpec->InSize += archiveFileInfo.Size +
|
||||
archiveLink.VolumesSize;
|
||||
extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize;
|
||||
if (!errorMessage.IsEmpty())
|
||||
return E_FAIL;
|
||||
}
|
||||
stat.NumFolders = extractCallbackSpec->NumFolders;
|
||||
stat.NumFiles = extractCallbackSpec->NumFiles;
|
||||
stat.UnpackSize = extractCallbackSpec->UnpackSize;
|
||||
stat.NumArchives = archivePaths.Size();
|
||||
stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;
|
||||
return S_OK;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Extract.h
|
||||
|
||||
#ifndef __EXTRACT_H
|
||||
#define __EXTRACT_H
|
||||
|
||||
#include "Common/Wildcard.h"
|
||||
#include "Windows/FileFind.h"
|
||||
|
||||
#include "../../Archive/IArchive.h"
|
||||
|
||||
#include "ArchiveExtractCallback.h"
|
||||
#include "ArchiveOpenCallback.h"
|
||||
#include "ExtractMode.h"
|
||||
#include "Property.h"
|
||||
|
||||
#include "../Common/LoadCodecs.h"
|
||||
|
||||
class CExtractOptions
|
||||
{
|
||||
public:
|
||||
bool StdOutMode;
|
||||
bool TestMode;
|
||||
NExtract::NPathMode::EEnum PathMode;
|
||||
|
||||
UString OutputDir;
|
||||
bool YesToAll;
|
||||
UString DefaultItemName;
|
||||
NWindows::NFile::NFind::CFileInfoW ArchiveFileInfo;
|
||||
|
||||
// bool ShowDialog;
|
||||
// bool PasswordEnabled;
|
||||
// UString Password;
|
||||
#ifdef COMPRESS_MT
|
||||
CObjectVector<CProperty> Properties;
|
||||
#endif
|
||||
|
||||
NExtract::NOverwriteMode::EEnum OverwriteMode;
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
CCodecs *Codecs;
|
||||
#endif
|
||||
|
||||
CExtractOptions():
|
||||
StdOutMode(false),
|
||||
YesToAll(false),
|
||||
TestMode(false),
|
||||
PathMode(NExtract::NPathMode::kFullPathnames),
|
||||
OverwriteMode(NExtract::NOverwriteMode::kAskBefore)
|
||||
{}
|
||||
|
||||
/*
|
||||
bool FullPathMode() const { return (ExtractMode == NExtractMode::kTest) ||
|
||||
(ExtractMode == NExtractMode::kFullPath); }
|
||||
*/
|
||||
};
|
||||
|
||||
struct CDecompressStat
|
||||
{
|
||||
UInt64 NumArchives;
|
||||
UInt64 UnpackSize;
|
||||
UInt64 PackSize;
|
||||
UInt64 NumFolders;
|
||||
UInt64 NumFiles;
|
||||
void Clear() { NumArchives = PackSize = UnpackSize = NumFolders = NumFiles = 0; }
|
||||
};
|
||||
|
||||
HRESULT DecompressArchives(
|
||||
CCodecs *codecs,
|
||||
UStringVector &archivePaths, UStringVector &archivePathsFull,
|
||||
const NWildcard::CCensorNode &wildcardCensor,
|
||||
const CExtractOptions &options,
|
||||
IOpenCallbackUI *openCallback,
|
||||
IExtractCallbackUI *extractCallback,
|
||||
UString &errorMessage,
|
||||
CDecompressStat &stat);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
// ExtractMode.h
|
||||
|
||||
#ifndef __EXTRACT_MODE_H
|
||||
#define __EXTRACT_MODE_H
|
||||
|
||||
namespace NExtract {
|
||||
|
||||
namespace NPathMode
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kFullPathnames,
|
||||
kCurrentPathnames,
|
||||
kNoPathnames
|
||||
};
|
||||
}
|
||||
|
||||
namespace NOverwriteMode
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kAskBefore,
|
||||
kWithoutPrompt,
|
||||
kSkipExisting,
|
||||
kAutoRename,
|
||||
kAutoRenameExisting
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,96 @@
|
||||
// ExtractingFilePath.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "ExtractingFilePath.h"
|
||||
|
||||
static UString ReplaceIncorrectChars(const UString &s)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
UString res;
|
||||
for (int i = 0; i < s.Length(); i++)
|
||||
{
|
||||
wchar_t c = s[i];
|
||||
if (c < 0x20 || c == '*' || c == '?' || c == '<' || c == '>' || c == '|' || c == ':' || c == '"')
|
||||
c = '_';
|
||||
res += c;
|
||||
}
|
||||
return res;
|
||||
#else
|
||||
return s;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static const wchar_t *g_ReservedNames[] =
|
||||
{
|
||||
L"CON", L"PRN", L"AUX", L"NUL"
|
||||
};
|
||||
|
||||
static bool CheckTail(const UString &name, int len)
|
||||
{
|
||||
int dotPos = name.Find(L'.');
|
||||
if (dotPos < 0)
|
||||
dotPos = name.Length();
|
||||
UString s = name.Left(dotPos);
|
||||
s.TrimRight();
|
||||
return (s.Length() != len);
|
||||
}
|
||||
|
||||
static bool CheckNameNum(const UString &name, const wchar_t *reservedName)
|
||||
{
|
||||
int len = MyStringLen(reservedName);
|
||||
if (name.Length() <= len)
|
||||
return true;
|
||||
if (name.Left(len).CompareNoCase(reservedName) != 0)
|
||||
return true;
|
||||
wchar_t c = name[len];
|
||||
if (c < L'0' || c > L'9')
|
||||
return true;
|
||||
return CheckTail(name, len + 1);
|
||||
}
|
||||
|
||||
static bool IsSupportedName(const UString &name)
|
||||
{
|
||||
for (int i = 0; i < sizeof(g_ReservedNames) / sizeof(g_ReservedNames[0]); i++)
|
||||
{
|
||||
const wchar_t *reservedName = g_ReservedNames[i];
|
||||
int len = MyStringLen(reservedName);
|
||||
if (name.Length() < len)
|
||||
continue;
|
||||
if (name.Left(len).CompareNoCase(reservedName) != 0)
|
||||
continue;
|
||||
if (!CheckTail(name, len))
|
||||
return false;
|
||||
}
|
||||
if (!CheckNameNum(name, L"COM"))
|
||||
return false;
|
||||
return CheckNameNum(name, L"LPT");
|
||||
}
|
||||
#endif
|
||||
|
||||
static UString GetCorrectFileName(const UString &path)
|
||||
{
|
||||
if (path == L".." || path == L".")
|
||||
return UString();
|
||||
return ReplaceIncorrectChars(path);
|
||||
}
|
||||
|
||||
void MakeCorrectPath(UStringVector &pathParts)
|
||||
{
|
||||
for (int i = 0; i < pathParts.Size();)
|
||||
{
|
||||
UString &s = pathParts[i];
|
||||
s = GetCorrectFileName(s);
|
||||
if (s.IsEmpty())
|
||||
pathParts.Delete(i);
|
||||
else
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!IsSupportedName(s))
|
||||
s = (UString)L"_" + s;
|
||||
#endif
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// ExtractingFilePath.h
|
||||
|
||||
#ifndef __EXTRACTINGFILEPATH_H
|
||||
#define __EXTRACTINGFILEPATH_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
|
||||
void MakeCorrectPath(UStringVector &pathParts);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
// IFileExtractCallback.h
|
||||
|
||||
#ifndef __IFILEEXTRACTCALLBACK_H
|
||||
#define __IFILEEXTRACTCALLBACK_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
#include "../../IDecl.h"
|
||||
|
||||
namespace NOverwriteAnswer
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kYes,
|
||||
kYesToAll,
|
||||
kNo,
|
||||
kNoToAll,
|
||||
kAutoRename,
|
||||
kCancel
|
||||
};
|
||||
}
|
||||
|
||||
DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07)
|
||||
{
|
||||
public:
|
||||
STDMETHOD(AskOverwrite)(
|
||||
const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
|
||||
const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
|
||||
Int32 *answer) PURE;
|
||||
STDMETHOD(PrepareOperation)(const wchar_t *name, bool isFolder, Int32 askExtractMode, const UInt64 *position) PURE;
|
||||
STDMETHOD(MessageError)(const wchar_t *message) PURE;
|
||||
STDMETHOD(SetOperationResult)(Int32 operationResult, bool encrypted) PURE;
|
||||
};
|
||||
|
||||
struct IExtractCallbackUI: IFolderArchiveExtractCallback
|
||||
{
|
||||
virtual HRESULT BeforeOpen(const wchar_t *name) = 0;
|
||||
virtual HRESULT OpenResult(const wchar_t *name, HRESULT result, bool encrypted) = 0;
|
||||
virtual HRESULT ThereAreNoFiles() = 0;
|
||||
virtual HRESULT ExtractResult(HRESULT result) = 0;
|
||||
virtual HRESULT SetPassword(const UString &password) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,644 @@
|
||||
// LoadCodecs.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "LoadCodecs.h"
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#ifdef NEW_FOLDER_INTERFACE
|
||||
#include "../../../Common/StringToInt.h"
|
||||
#endif
|
||||
#include "../../../Windows/PropVariant.h"
|
||||
|
||||
#include "../../ICoder.h"
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
#include "../../../Windows/FileFind.h"
|
||||
#include "../../../Windows/DLL.h"
|
||||
#ifdef NEW_FOLDER_INTERFACE
|
||||
#include "../../../Windows/ResourceString.h"
|
||||
static const UINT kIconTypesResId = 100;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Windows/Registry.h"
|
||||
#endif
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NFile;
|
||||
|
||||
#ifdef _WIN32
|
||||
extern HINSTANCE g_hInstance;
|
||||
#endif
|
||||
|
||||
static CSysString GetLibraryFolderPrefix()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
TCHAR fullPath[MAX_PATH + 1];
|
||||
::GetModuleFileName(g_hInstance, fullPath, MAX_PATH);
|
||||
CSysString path = fullPath;
|
||||
int pos = path.ReverseFind(TEXT(CHAR_PATH_SEPARATOR));
|
||||
return path.Left(pos + 1);
|
||||
#else
|
||||
return CSysString(); // FIX IT
|
||||
#endif
|
||||
}
|
||||
|
||||
#define kCodecsFolderName TEXT("Codecs")
|
||||
#define kFormatsFolderName TEXT("Formats")
|
||||
static TCHAR *kMainDll = TEXT("7z.dll");
|
||||
|
||||
#ifdef _WIN32
|
||||
static LPCTSTR kRegistryPath = TEXT("Software\\7-zip");
|
||||
static LPCTSTR kProgramPathValue = TEXT("Path");
|
||||
static bool ReadPathFromRegistry(HKEY baseKey, CSysString &path)
|
||||
{
|
||||
NRegistry::CKey key;
|
||||
if(key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
|
||||
if (key.QueryValue(kProgramPathValue, path) == ERROR_SUCCESS)
|
||||
{
|
||||
NName::NormalizeDirPathPrefix(path);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
CSysString GetBaseFolderPrefixFromRegistry()
|
||||
{
|
||||
CSysString moduleFolderPrefix = GetLibraryFolderPrefix();
|
||||
NFind::CFileInfo fileInfo;
|
||||
if (NFind::FindFile(moduleFolderPrefix + kMainDll, fileInfo))
|
||||
if (!fileInfo.IsDirectory())
|
||||
return moduleFolderPrefix;
|
||||
if (NFind::FindFile(moduleFolderPrefix + kCodecsFolderName, fileInfo))
|
||||
if (fileInfo.IsDirectory())
|
||||
return moduleFolderPrefix;
|
||||
if (NFind::FindFile(moduleFolderPrefix + kFormatsFolderName, fileInfo))
|
||||
if (fileInfo.IsDirectory())
|
||||
return moduleFolderPrefix;
|
||||
#ifdef _WIN32
|
||||
CSysString path;
|
||||
if (ReadPathFromRegistry(HKEY_CURRENT_USER, path))
|
||||
return path;
|
||||
if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path))
|
||||
return path;
|
||||
#endif
|
||||
return moduleFolderPrefix;
|
||||
}
|
||||
|
||||
typedef UInt32 (WINAPI *GetNumberOfMethodsFunc)(UInt32 *numMethods);
|
||||
typedef UInt32 (WINAPI *GetNumberOfFormatsFunc)(UInt32 *numFormats);
|
||||
typedef UInt32 (WINAPI *GetHandlerPropertyFunc)(PROPID propID, PROPVARIANT *value);
|
||||
typedef UInt32 (WINAPI *GetHandlerPropertyFunc2)(UInt32 index, PROPID propID, PROPVARIANT *value);
|
||||
typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *iid, void **outObject);
|
||||
typedef UInt32 (WINAPI *SetLargePageModeFunc)();
|
||||
|
||||
|
||||
static HRESULT GetCoderClass(GetMethodPropertyFunc getMethodProperty, UInt32 index,
|
||||
PROPID propId, CLSID &clsId, bool &isAssigned)
|
||||
{
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
isAssigned = false;
|
||||
RINOK(getMethodProperty(index, propId, &prop));
|
||||
if (prop.vt == VT_BSTR)
|
||||
{
|
||||
isAssigned = true;
|
||||
clsId = *(const GUID *)prop.bstrVal;
|
||||
}
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CCodecs::LoadCodecs()
|
||||
{
|
||||
CCodecLib &lib = Libs.Back();
|
||||
lib.GetMethodProperty = (GetMethodPropertyFunc)lib.Lib.GetProcAddress("GetMethodProperty");
|
||||
if (lib.GetMethodProperty == NULL)
|
||||
return S_OK;
|
||||
|
||||
UInt32 numMethods = 1;
|
||||
GetNumberOfMethodsFunc getNumberOfMethodsFunc = (GetNumberOfMethodsFunc)lib.Lib.GetProcAddress("GetNumberOfMethods");
|
||||
if (getNumberOfMethodsFunc != NULL)
|
||||
{
|
||||
RINOK(getNumberOfMethodsFunc(&numMethods));
|
||||
}
|
||||
|
||||
for(UInt32 i = 0; i < numMethods; i++)
|
||||
{
|
||||
CDllCodecInfo info;
|
||||
info.LibIndex = Libs.Size() - 1;
|
||||
info.CodecIndex = i;
|
||||
|
||||
RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned));
|
||||
RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned));
|
||||
|
||||
Codecs.Add(info);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ReadProp(
|
||||
GetHandlerPropertyFunc getProp,
|
||||
GetHandlerPropertyFunc2 getProp2,
|
||||
UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
|
||||
{
|
||||
if (getProp2)
|
||||
return getProp2(index, propID, &prop);;
|
||||
return getProp(propID, &prop);
|
||||
}
|
||||
|
||||
static HRESULT ReadBoolProp(
|
||||
GetHandlerPropertyFunc getProp,
|
||||
GetHandlerPropertyFunc2 getProp2,
|
||||
UInt32 index, PROPID propID, bool &res)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(ReadProp(getProp, getProp2, index, propID, prop));
|
||||
if (prop.vt == VT_BOOL)
|
||||
res = VARIANT_BOOLToBool(prop.boolVal);
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT ReadStringProp(
|
||||
GetHandlerPropertyFunc getProp,
|
||||
GetHandlerPropertyFunc2 getProp2,
|
||||
UInt32 index, PROPID propID, UString &res)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(ReadProp(getProp, getProp2, index, propID, prop));
|
||||
if (prop.vt == VT_BSTR)
|
||||
res = prop.bstrVal;
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const unsigned int kNumArcsMax = 32;
|
||||
static unsigned int g_NumArcs = 0;
|
||||
static const CArcInfo *g_Arcs[kNumArcsMax];
|
||||
void RegisterArc(const CArcInfo *arcInfo)
|
||||
{
|
||||
if (g_NumArcs < kNumArcsMax)
|
||||
g_Arcs[g_NumArcs++] = arcInfo;
|
||||
}
|
||||
|
||||
static void SplitString(const UString &srcString, UStringVector &destStrings)
|
||||
{
|
||||
destStrings.Clear();
|
||||
UString s;
|
||||
int len = srcString.Length();
|
||||
if (len == 0)
|
||||
return;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
wchar_t c = srcString[i];
|
||||
if (c == L' ')
|
||||
{
|
||||
if (!s.IsEmpty())
|
||||
{
|
||||
destStrings.Add(s);
|
||||
s.Empty();
|
||||
}
|
||||
}
|
||||
else
|
||||
s += c;
|
||||
}
|
||||
if (!s.IsEmpty())
|
||||
destStrings.Add(s);
|
||||
}
|
||||
|
||||
void CArcInfoEx::AddExts(const wchar_t* ext, const wchar_t* addExt)
|
||||
{
|
||||
UStringVector exts, addExts;
|
||||
SplitString(ext, exts);
|
||||
if (addExt != 0)
|
||||
SplitString(addExt, addExts);
|
||||
for (int i = 0; i < exts.Size(); i++)
|
||||
{
|
||||
CArcExtInfo extInfo;
|
||||
extInfo.Ext = exts[i];
|
||||
if (i < addExts.Size())
|
||||
{
|
||||
extInfo.AddExt = addExts[i];
|
||||
if (extInfo.AddExt == L"*")
|
||||
extInfo.AddExt.Empty();
|
||||
}
|
||||
Exts.Add(extInfo);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
|
||||
HRESULT CCodecs::LoadFormats()
|
||||
{
|
||||
const NDLL::CLibrary &lib = Libs.Back().Lib;
|
||||
GetHandlerPropertyFunc getProp = 0;
|
||||
GetHandlerPropertyFunc2 getProp2 = (GetHandlerPropertyFunc2)
|
||||
lib.GetProcAddress("GetHandlerProperty2");
|
||||
if (getProp2 == NULL)
|
||||
{
|
||||
getProp = (GetHandlerPropertyFunc)
|
||||
lib.GetProcAddress("GetHandlerProperty");
|
||||
if (getProp == NULL)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
UInt32 numFormats = 1;
|
||||
GetNumberOfFormatsFunc getNumberOfFormats = (GetNumberOfFormatsFunc)
|
||||
lib.GetProcAddress("GetNumberOfFormats");
|
||||
if (getNumberOfFormats != NULL)
|
||||
{
|
||||
RINOK(getNumberOfFormats(&numFormats));
|
||||
}
|
||||
if (getProp2 == NULL)
|
||||
numFormats = 1;
|
||||
|
||||
for(UInt32 i = 0; i < numFormats; i++)
|
||||
{
|
||||
CArcInfoEx item;
|
||||
item.LibIndex = Libs.Size() - 1;
|
||||
item.FormatIndex = i;
|
||||
|
||||
RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kName, item.Name));
|
||||
|
||||
NCOM::CPropVariant prop;
|
||||
if (ReadProp(getProp, getProp2, i, NArchive::kClassID, prop) != S_OK)
|
||||
continue;
|
||||
if (prop.vt != VT_BSTR)
|
||||
continue;
|
||||
item.ClassID = *(const GUID *)prop.bstrVal;
|
||||
prop.Clear();
|
||||
|
||||
UString ext, addExt;
|
||||
RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kExtension, ext));
|
||||
RINOK(ReadStringProp(getProp, getProp2, i, NArchive::kAddExtension, addExt));
|
||||
item.AddExts(ext, addExt);
|
||||
|
||||
ReadBoolProp(getProp, getProp2, i, NArchive::kUpdate, item.UpdateEnabled);
|
||||
if (item.UpdateEnabled)
|
||||
ReadBoolProp(getProp, getProp2, i, NArchive::kKeepName, item.KeepName);
|
||||
|
||||
if (ReadProp(getProp, getProp2, i, NArchive::kStartSignature, prop) == S_OK)
|
||||
if (prop.vt == VT_BSTR)
|
||||
{
|
||||
UINT len = ::SysStringByteLen(prop.bstrVal);
|
||||
item.StartSignature.SetCapacity(len);
|
||||
memmove(item.StartSignature, prop.bstrVal, len);
|
||||
}
|
||||
Formats.Add(item);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef NEW_FOLDER_INTERFACE
|
||||
void CCodecLib::LoadIcons()
|
||||
{
|
||||
UString iconTypes = MyLoadStringW((HMODULE)Lib, kIconTypesResId);
|
||||
UStringVector pairs;
|
||||
SplitString(iconTypes, pairs);
|
||||
for (int i = 0; i < pairs.Size(); i++)
|
||||
{
|
||||
const UString &s = pairs[i];
|
||||
int pos = s.Find(L':');
|
||||
if (pos < 0)
|
||||
continue;
|
||||
CIconPair iconPair;
|
||||
const wchar_t *end;
|
||||
UString num = s.Mid(pos + 1);
|
||||
iconPair.IconIndex = (UInt32)ConvertStringToUInt64(num, &end);
|
||||
if (*end != L'\0')
|
||||
continue;
|
||||
iconPair.Ext = s.Left(pos);
|
||||
IconPairs.Add(iconPair);
|
||||
}
|
||||
}
|
||||
|
||||
int CCodecLib::FindIconIndex(const UString &ext) const
|
||||
{
|
||||
for (int i = 0; i < IconPairs.Size(); i++)
|
||||
{
|
||||
const CIconPair &pair = IconPairs[i];
|
||||
if (ext.CompareNoCase(pair.Ext) == 0)
|
||||
return pair.IconIndex;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
extern "C"
|
||||
{
|
||||
extern SIZE_T g_LargePageSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT CCodecs::LoadDll(const CSysString &dllPath)
|
||||
{
|
||||
{
|
||||
NDLL::CLibrary library;
|
||||
if (!library.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
|
||||
return S_OK;
|
||||
}
|
||||
Libs.Add(CCodecLib());
|
||||
CCodecLib &lib = Libs.Back();
|
||||
#ifdef NEW_FOLDER_INTERFACE
|
||||
lib.Path = dllPath;
|
||||
#endif
|
||||
bool used = false;
|
||||
HRESULT res = S_OK;
|
||||
if (lib.Lib.Load(dllPath))
|
||||
{
|
||||
#ifdef NEW_FOLDER_INTERFACE
|
||||
lib.LoadIcons();
|
||||
#endif
|
||||
|
||||
#ifdef _7ZIP_LARGE_PAGES
|
||||
if (g_LargePageSize != 0)
|
||||
{
|
||||
SetLargePageModeFunc setLargePageMode = (SetLargePageModeFunc)lib.Lib.GetProcAddress("SetLargePageMode");
|
||||
if (setLargePageMode != 0)
|
||||
setLargePageMode();
|
||||
}
|
||||
#endif
|
||||
|
||||
lib.CreateObject = (CreateObjectFunc)lib.Lib.GetProcAddress("CreateObject");
|
||||
if (lib.CreateObject != 0)
|
||||
{
|
||||
int startSize = Codecs.Size();
|
||||
res = LoadCodecs();
|
||||
used = (Codecs.Size() != startSize);
|
||||
if (res == S_OK)
|
||||
{
|
||||
startSize = Formats.Size();
|
||||
res = LoadFormats();
|
||||
used = used || (Formats.Size() != startSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!used)
|
||||
Libs.DeleteBack();
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT CCodecs::LoadDllsFromFolder(const CSysString &folderPrefix)
|
||||
{
|
||||
NFile::NFind::CEnumerator enumerator(folderPrefix + CSysString(TEXT("*")));
|
||||
NFile::NFind::CFileInfo fileInfo;
|
||||
while (enumerator.Next(fileInfo))
|
||||
{
|
||||
if (fileInfo.IsDirectory())
|
||||
continue;
|
||||
RINOK(LoadDll(folderPrefix + fileInfo.Name));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _SFX
|
||||
static inline void SetBuffer(CByteBuffer &bb, const Byte *data, int size)
|
||||
{
|
||||
bb.SetCapacity(size);
|
||||
memmove((Byte *)bb, data, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT CCodecs::Load()
|
||||
{
|
||||
Formats.Clear();
|
||||
#ifdef EXTERNAL_CODECS
|
||||
Codecs.Clear();
|
||||
#endif
|
||||
for (UInt32 i = 0; i < g_NumArcs; i++)
|
||||
{
|
||||
const CArcInfo &arc = *g_Arcs[i];
|
||||
CArcInfoEx item;
|
||||
item.Name = arc.Name;
|
||||
item.CreateInArchive = arc.CreateInArchive;
|
||||
item.CreateOutArchive = arc.CreateOutArchive;
|
||||
item.AddExts(arc.Ext, arc.AddExt);
|
||||
item.UpdateEnabled = (arc.CreateOutArchive != 0);
|
||||
item.KeepName = arc.KeepName;
|
||||
|
||||
#ifndef _SFX
|
||||
SetBuffer(item.StartSignature, arc.Signature, arc.SignatureSize);
|
||||
#endif
|
||||
Formats.Add(item);
|
||||
}
|
||||
#ifdef EXTERNAL_CODECS
|
||||
const CSysString baseFolder = GetBaseFolderPrefixFromRegistry();
|
||||
RINOK(LoadDll(baseFolder + kMainDll));
|
||||
RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName TEXT(STRING_PATH_SEPARATOR)));
|
||||
RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName TEXT(STRING_PATH_SEPARATOR)));
|
||||
#endif
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int CCodecs::FindFormatForArchiveName(const UString &archivePath) const
|
||||
{
|
||||
int slashPos1 = archivePath.ReverseFind(L'\\');
|
||||
int slashPos2 = archivePath.ReverseFind(L'.');
|
||||
int dotPos = archivePath.ReverseFind(L'.');
|
||||
if (dotPos < 0 || dotPos < slashPos1 || dotPos < slashPos2)
|
||||
return -1;
|
||||
UString ext = archivePath.Mid(dotPos + 1);
|
||||
for (int i = 0; i < Formats.Size(); i++)
|
||||
{
|
||||
const CArcInfoEx &arc = Formats[i];
|
||||
if (!arc.UpdateEnabled)
|
||||
continue;
|
||||
// if (arc.FindExtension(ext) >= 0)
|
||||
UString mainExt = arc.GetMainExt();
|
||||
if (!mainExt.IsEmpty() && ext.CompareNoCase(mainExt) == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CCodecs::FindFormatForArchiveType(const UString &arcType) const
|
||||
{
|
||||
for (int i = 0; i < Formats.Size(); i++)
|
||||
{
|
||||
const CArcInfoEx &arc = Formats[i];
|
||||
if (!arc.UpdateEnabled)
|
||||
continue;
|
||||
if (arc.Name.CompareNoCase(arcType) == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
|
||||
#ifdef EXPORT_CODECS
|
||||
extern unsigned int g_NumCodecs;
|
||||
STDAPI CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject);
|
||||
STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
|
||||
// STDAPI GetNumberOfMethods(UINT32 *numCodecs);
|
||||
#endif
|
||||
|
||||
STDMETHODIMP CCodecs::GetNumberOfMethods(UINT32 *numMethods)
|
||||
{
|
||||
*numMethods =
|
||||
#ifdef EXPORT_CODECS
|
||||
g_NumCodecs +
|
||||
#endif
|
||||
Codecs.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CCodecs::GetProperty(UINT32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
#ifdef EXPORT_CODECS
|
||||
if (index < g_NumCodecs)
|
||||
return GetMethodProperty(index, propID, value);
|
||||
#endif
|
||||
|
||||
const CDllCodecInfo &ci = Codecs[index
|
||||
#ifdef EXPORT_CODECS
|
||||
- g_NumCodecs
|
||||
#endif
|
||||
];
|
||||
|
||||
if (propID == NMethodPropID::kDecoderIsAssigned)
|
||||
{
|
||||
NWindows::NCOM::CPropVariant propVariant;
|
||||
propVariant = ci.DecoderIsAssigned;
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
if (propID == NMethodPropID::kEncoderIsAssigned)
|
||||
{
|
||||
NWindows::NCOM::CPropVariant propVariant;
|
||||
propVariant = ci.EncoderIsAssigned;
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
return Libs[ci.LibIndex].GetMethodProperty(ci.CodecIndex, propID, value);
|
||||
}
|
||||
|
||||
STDMETHODIMP CCodecs::CreateDecoder(UINT32 index, const GUID *iid, void **coder)
|
||||
{
|
||||
#ifdef EXPORT_CODECS
|
||||
if (index < g_NumCodecs)
|
||||
return CreateCoder2(false, index, iid, coder);
|
||||
#endif
|
||||
const CDllCodecInfo &ci = Codecs[index
|
||||
#ifdef EXPORT_CODECS
|
||||
- g_NumCodecs
|
||||
#endif
|
||||
];
|
||||
if (ci.DecoderIsAssigned)
|
||||
return Libs[ci.LibIndex].CreateObject(&ci.Decoder, iid, (void **)coder);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CCodecs::CreateEncoder(UINT32 index, const GUID *iid, void **coder)
|
||||
{
|
||||
#ifdef EXPORT_CODECS
|
||||
if (index < g_NumCodecs)
|
||||
return CreateCoder2(true, index, iid, coder);
|
||||
#endif
|
||||
const CDllCodecInfo &ci = Codecs[index
|
||||
#ifdef EXPORT_CODECS
|
||||
- g_NumCodecs
|
||||
#endif
|
||||
];
|
||||
if (ci.EncoderIsAssigned)
|
||||
return Libs[ci.LibIndex].CreateObject(&ci.Encoder, iid, (void **)coder);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CCodecs::CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const
|
||||
{
|
||||
for (int i = 0; i < Codecs.Size(); i++)
|
||||
{
|
||||
const CDllCodecInfo &codec = Codecs[i];
|
||||
if (encode && !codec.EncoderIsAssigned || !encode && !codec.DecoderIsAssigned)
|
||||
continue;
|
||||
const CCodecLib &lib = Libs[codec.LibIndex];
|
||||
UString res;
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
RINOK(lib.GetMethodProperty(codec.CodecIndex, NMethodPropID::kName, &prop));
|
||||
if (prop.vt == VT_BSTR)
|
||||
res = prop.bstrVal;
|
||||
else if (prop.vt != VT_EMPTY)
|
||||
continue;
|
||||
if (name.CompareNoCase(res) == 0)
|
||||
return lib.CreateObject(encode ? &codec.Encoder : &codec.Decoder, &IID_ICompressCoder, (void **)&coder);
|
||||
}
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
int CCodecs::GetCodecLibIndex(UInt32 index)
|
||||
{
|
||||
#ifdef EXPORT_CODECS
|
||||
if (index < g_NumCodecs)
|
||||
return -1;
|
||||
#endif
|
||||
#ifdef EXTERNAL_CODECS
|
||||
const CDllCodecInfo &ci = Codecs[index
|
||||
#ifdef EXPORT_CODECS
|
||||
- g_NumCodecs
|
||||
#endif
|
||||
];
|
||||
return ci.LibIndex;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CCodecs::GetCodecEncoderIsAssigned(UInt32 index)
|
||||
{
|
||||
#ifdef EXPORT_CODECS
|
||||
if (index < g_NumCodecs)
|
||||
{
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
if (GetProperty(index, NMethodPropID::kEncoder, &prop) == S_OK)
|
||||
if (prop.vt != VT_EMPTY)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#ifdef EXTERNAL_CODECS
|
||||
const CDllCodecInfo &ci = Codecs[index
|
||||
#ifdef EXPORT_CODECS
|
||||
- g_NumCodecs
|
||||
#endif
|
||||
];
|
||||
return ci.EncoderIsAssigned;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
HRESULT CCodecs::GetCodecId(UInt32 index, UInt64 &id)
|
||||
{
|
||||
UString s;
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
RINOK(GetProperty(index, NMethodPropID::kID, &prop));
|
||||
if (prop.vt != VT_UI8)
|
||||
return E_INVALIDARG;
|
||||
id = prop.uhVal.QuadPart;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
UString CCodecs::GetCodecName(UInt32 index)
|
||||
{
|
||||
UString s;
|
||||
NWindows::NCOM::CPropVariant prop;
|
||||
if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
|
||||
if (prop.vt == VT_BSTR)
|
||||
s = prop.bstrVal;
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,215 @@
|
||||
// LoadCodecs.h
|
||||
|
||||
#ifndef __LOADCODECS_H
|
||||
#define __LOADCODECS_H
|
||||
|
||||
#include "../../../Common/Types.h"
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../../Common/MyString.h"
|
||||
#include "../../../Common/Buffer.h"
|
||||
#include "../../ICoder.h"
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
#include "../../../Windows/DLL.h"
|
||||
#endif
|
||||
|
||||
struct CDllCodecInfo
|
||||
{
|
||||
CLSID Encoder;
|
||||
CLSID Decoder;
|
||||
bool EncoderIsAssigned;
|
||||
bool DecoderIsAssigned;
|
||||
int LibIndex;
|
||||
UInt32 CodecIndex;
|
||||
};
|
||||
|
||||
#include "../../Archive/IArchive.h"
|
||||
|
||||
typedef IInArchive * (*CreateInArchiveP)();
|
||||
typedef IOutArchive * (*CreateOutArchiveP)();
|
||||
|
||||
struct CArcExtInfo
|
||||
{
|
||||
UString Ext;
|
||||
UString AddExt;
|
||||
CArcExtInfo() {}
|
||||
CArcExtInfo(const UString &ext): Ext(ext) {}
|
||||
CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
|
||||
};
|
||||
|
||||
|
||||
struct CArcInfoEx
|
||||
{
|
||||
#ifdef EXTERNAL_CODECS
|
||||
int LibIndex;
|
||||
UInt32 FormatIndex;
|
||||
CLSID ClassID;
|
||||
#endif
|
||||
bool UpdateEnabled;
|
||||
CreateInArchiveP CreateInArchive;
|
||||
CreateOutArchiveP CreateOutArchive;
|
||||
UString Name;
|
||||
CObjectVector<CArcExtInfo> Exts;
|
||||
#ifndef _SFX
|
||||
CByteBuffer StartSignature;
|
||||
// CByteBuffer FinishSignature;
|
||||
#ifdef NEW_FOLDER_INTERFACE
|
||||
UStringVector AssociateExts;
|
||||
#endif
|
||||
#endif
|
||||
bool KeepName;
|
||||
UString GetMainExt() const
|
||||
{
|
||||
if (Exts.IsEmpty())
|
||||
return UString();
|
||||
return Exts[0].Ext;
|
||||
}
|
||||
int FindExtension(const UString &ext) const
|
||||
{
|
||||
for (int i = 0; i < Exts.Size(); i++)
|
||||
if (ext.CompareNoCase(Exts[i].Ext) == 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
UString GetAllExtensions() const
|
||||
{
|
||||
UString s;
|
||||
for (int i = 0; i < Exts.Size(); i++)
|
||||
{
|
||||
if (i > 0)
|
||||
s += ' ';
|
||||
s += Exts[i].Ext;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void AddExts(const wchar_t* ext, const wchar_t* addExt);
|
||||
|
||||
CArcInfoEx():
|
||||
#ifdef EXTERNAL_CODECS
|
||||
LibIndex(-1),
|
||||
#endif
|
||||
UpdateEnabled(false),
|
||||
CreateInArchive(0), CreateOutArchive(0),
|
||||
KeepName(false)
|
||||
#ifndef _SFX
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
typedef UInt32 (WINAPI *GetMethodPropertyFunc)(UInt32 index, PROPID propID, PROPVARIANT *value);
|
||||
typedef UInt32 (WINAPI *CreateObjectFunc)(const GUID *clsID, const GUID *interfaceID, void **outObject);
|
||||
|
||||
|
||||
struct CCodecLib
|
||||
{
|
||||
NWindows::NDLL::CLibrary Lib;
|
||||
GetMethodPropertyFunc GetMethodProperty;
|
||||
CreateObjectFunc CreateObject;
|
||||
#ifdef NEW_FOLDER_INTERFACE
|
||||
struct CIconPair
|
||||
{
|
||||
UString Ext;
|
||||
UInt32 IconIndex;
|
||||
};
|
||||
CSysString Path;
|
||||
CObjectVector<CIconPair> IconPairs;
|
||||
void LoadIcons();
|
||||
int FindIconIndex(const UString &ext) const;
|
||||
#endif
|
||||
CCodecLib(): GetMethodProperty(0) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
class CCodecs:
|
||||
#ifdef EXTERNAL_CODECS
|
||||
public ICompressCodecsInfo,
|
||||
#else
|
||||
public IUnknown,
|
||||
#endif
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
#ifdef EXTERNAL_CODECS
|
||||
CObjectVector<CCodecLib> Libs;
|
||||
CObjectVector<CDllCodecInfo> Codecs;
|
||||
HRESULT LoadCodecs();
|
||||
HRESULT LoadFormats();
|
||||
HRESULT LoadDll(const CSysString &path);
|
||||
HRESULT LoadDllsFromFolder(const CSysString &folderPrefix);
|
||||
|
||||
HRESULT CreateArchiveHandler(const CArcInfoEx &ai, void **archive, bool outHandler) const
|
||||
{
|
||||
return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
CObjectVector<CArcInfoEx> Formats;
|
||||
HRESULT Load();
|
||||
int FindFormatForArchiveName(const UString &archivePath) const;
|
||||
int FindFormatForArchiveType(const UString &arcType) const;
|
||||
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
STDMETHOD(GetNumberOfMethods)(UINT32 *numMethods);
|
||||
STDMETHOD(GetProperty)(UINT32 index, PROPID propID, PROPVARIANT *value);
|
||||
STDMETHOD(CreateDecoder)(UINT32 index, const GUID *interfaceID, void **coder);
|
||||
STDMETHOD(CreateEncoder)(UINT32 index, const GUID *interfaceID, void **coder);
|
||||
#endif
|
||||
|
||||
int GetCodecLibIndex(UInt32 index);
|
||||
bool GetCodecEncoderIsAssigned(UInt32 index);
|
||||
HRESULT GetCodecId(UInt32 index, UInt64 &id);
|
||||
UString GetCodecName(UInt32 index);
|
||||
|
||||
HRESULT CreateInArchive(int formatIndex, CMyComPtr<IInArchive> &archive) const
|
||||
{
|
||||
const CArcInfoEx &ai = Formats[formatIndex];
|
||||
#ifdef EXTERNAL_CODECS
|
||||
if (ai.LibIndex < 0)
|
||||
#endif
|
||||
{
|
||||
archive = ai.CreateInArchive();
|
||||
return S_OK;
|
||||
}
|
||||
#ifdef EXTERNAL_CODECS
|
||||
return CreateArchiveHandler(ai, (void **)&archive, false);
|
||||
#endif
|
||||
}
|
||||
HRESULT CreateOutArchive(int formatIndex, CMyComPtr<IOutArchive> &archive) const
|
||||
{
|
||||
const CArcInfoEx &ai = Formats[formatIndex];
|
||||
#ifdef EXTERNAL_CODECS
|
||||
if (ai.LibIndex < 0)
|
||||
#endif
|
||||
{
|
||||
archive = ai.CreateOutArchive();
|
||||
return S_OK;
|
||||
}
|
||||
#ifdef EXTERNAL_CODECS
|
||||
return CreateArchiveHandler(ai, (void **)&archive, true);
|
||||
#endif
|
||||
}
|
||||
int FindOutFormatFromName(const UString &name) const
|
||||
{
|
||||
for (int i = 0; i < Formats.Size(); i++)
|
||||
{
|
||||
const CArcInfoEx &arc = Formats[i];
|
||||
if (!arc.UpdateEnabled)
|
||||
continue;
|
||||
if (arc.Name.CompareNoCase(name) == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
HRESULT CreateCoder(const UString &name, bool encode, CMyComPtr<ICompressCoder> &coder) const;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,461 @@
|
||||
// OpenArchive.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "OpenArchive.h"
|
||||
|
||||
#include "Common/Wildcard.h"
|
||||
|
||||
#include "Windows/FileName.h"
|
||||
#include "Windows/FileDir.h"
|
||||
#include "Windows/Defs.h"
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../Common/FileStreams.h"
|
||||
#include "../../Common/StreamUtils.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
|
||||
#include "DefaultName.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(archive->GetProperty(index, kpidPath, &prop));
|
||||
if(prop.vt == VT_BSTR)
|
||||
result = prop.bstrVal;
|
||||
else if (prop.vt == VT_EMPTY)
|
||||
result.Empty();
|
||||
else
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result)
|
||||
{
|
||||
RINOK(GetArchiveItemPath(archive, index, result));
|
||||
if (result.IsEmpty())
|
||||
result = defaultName;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index,
|
||||
const FILETIME &defaultFileTime, FILETIME &fileTime)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(archive->GetProperty(index, kpidLastWriteTime, &prop));
|
||||
if (prop.vt == VT_FILETIME)
|
||||
fileTime = prop.filetime;
|
||||
else if (prop.vt == VT_EMPTY)
|
||||
fileTime = defaultFileTime;
|
||||
else
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
|
||||
{
|
||||
NCOM::CPropVariant prop;
|
||||
RINOK(archive->GetProperty(index, propID, &prop));
|
||||
if(prop.vt == VT_BOOL)
|
||||
result = VARIANT_BOOLToBool(prop.boolVal);
|
||||
else if (prop.vt == VT_EMPTY)
|
||||
result = false;
|
||||
else
|
||||
return E_FAIL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
|
||||
{
|
||||
return IsArchiveItemProp(archive, index, kpidIsFolder, result);
|
||||
}
|
||||
|
||||
HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result)
|
||||
{
|
||||
return IsArchiveItemProp(archive, index, kpidIsAnti, result);
|
||||
}
|
||||
|
||||
// Static-SFX (for Linux) can be big.
|
||||
const UInt64 kMaxCheckStartPosition = 1 << 22;
|
||||
|
||||
HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName, IArchiveOpenCallback *openArchiveCallback)
|
||||
{
|
||||
CInFileStream *inStreamSpec = new CInFileStream;
|
||||
CMyComPtr<IInStream> inStream(inStreamSpec);
|
||||
inStreamSpec->Open(fileName);
|
||||
return archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback);
|
||||
}
|
||||
|
||||
#ifndef _SFX
|
||||
static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
|
||||
{
|
||||
for (size_t i = 0; i < size; i++)
|
||||
if (p1[i] != p2[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT OpenArchive(
|
||||
CCodecs *codecs,
|
||||
IInStream *inStream,
|
||||
const UString &fileName,
|
||||
IInArchive **archiveResult,
|
||||
int &formatIndex,
|
||||
UString &defaultItemName,
|
||||
IArchiveOpenCallback *openArchiveCallback)
|
||||
{
|
||||
*archiveResult = NULL;
|
||||
UString extension;
|
||||
{
|
||||
int dotPos = fileName.ReverseFind(L'.');
|
||||
if (dotPos >= 0)
|
||||
extension = fileName.Mid(dotPos + 1);
|
||||
}
|
||||
CIntVector orderIndices;
|
||||
int i;
|
||||
int numFinded = 0;
|
||||
for (i = 0; i < codecs->Formats.Size(); i++)
|
||||
if (codecs->Formats[i].FindExtension(extension) >= 0)
|
||||
orderIndices.Insert(numFinded++, i);
|
||||
else
|
||||
orderIndices.Add(i);
|
||||
|
||||
#ifndef _SFX
|
||||
if (numFinded != 1)
|
||||
{
|
||||
CIntVector orderIndices2;
|
||||
CByteBuffer byteBuffer;
|
||||
const UInt32 kBufferSize = (200 << 10);
|
||||
byteBuffer.SetCapacity(kBufferSize);
|
||||
Byte *buffer = byteBuffer;
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
UInt32 processedSize;
|
||||
RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize));
|
||||
for (UInt32 pos = 0; pos < processedSize; pos++)
|
||||
{
|
||||
for (int i = 0; i < orderIndices.Size(); i++)
|
||||
{
|
||||
int index = orderIndices[i];
|
||||
const CArcInfoEx &ai = codecs->Formats[index];
|
||||
const CByteBuffer &sig = ai.StartSignature;
|
||||
if (sig.GetCapacity() == 0)
|
||||
continue;
|
||||
if (pos + sig.GetCapacity() > processedSize)
|
||||
continue;
|
||||
if (TestSignature(buffer + pos, sig, sig.GetCapacity()))
|
||||
{
|
||||
orderIndices2.Add(index);
|
||||
orderIndices.Delete(i--);
|
||||
}
|
||||
}
|
||||
}
|
||||
orderIndices2 += orderIndices;
|
||||
orderIndices = orderIndices2;
|
||||
}
|
||||
else if (extension == L"000" || extension == L"001")
|
||||
{
|
||||
CByteBuffer byteBuffer;
|
||||
const UInt32 kBufferSize = (1 << 10);
|
||||
byteBuffer.SetCapacity(kBufferSize);
|
||||
Byte *buffer = byteBuffer;
|
||||
RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
|
||||
UInt32 processedSize;
|
||||
RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize));
|
||||
if (processedSize >= 16)
|
||||
{
|
||||
Byte kRarHeader[] = {0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
|
||||
if (TestSignature(buffer, kRarHeader, 7) && buffer[9] == 0x73 && (buffer[10] && 1) != 0)
|
||||
{
|
||||
for (int i = 0; i < orderIndices.Size(); i++)
|
||||
{
|
||||
int index = orderIndices[i];
|
||||
const CArcInfoEx &ai = codecs->Formats[index];
|
||||
if (ai.Name.CompareNoCase(L"rar") != 0)
|
||||
continue;
|
||||
orderIndices.Delete(i--);
|
||||
orderIndices.Insert(0, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT badResult = S_OK;
|
||||
for(i = 0; i < orderIndices.Size(); i++)
|
||||
{
|
||||
inStream->Seek(0, STREAM_SEEK_SET, NULL);
|
||||
|
||||
CMyComPtr<IInArchive> archive;
|
||||
|
||||
formatIndex = orderIndices[i];
|
||||
RINOK(codecs->CreateInArchive(formatIndex, archive));
|
||||
if (!archive)
|
||||
continue;
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
{
|
||||
CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
|
||||
archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
|
||||
if (setCompressCodecsInfo)
|
||||
{
|
||||
RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
HRESULT result = archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback);
|
||||
if (result == S_FALSE)
|
||||
continue;
|
||||
if(result != S_OK)
|
||||
{
|
||||
badResult = result;
|
||||
if(result == E_ABORT)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
*archiveResult = archive.Detach();
|
||||
const CArcInfoEx &format = codecs->Formats[formatIndex];
|
||||
if (format.Exts.Size() == 0)
|
||||
{
|
||||
defaultItemName = GetDefaultName2(fileName, L"", L"");
|
||||
}
|
||||
else
|
||||
{
|
||||
int subExtIndex = format.FindExtension(extension);
|
||||
if (subExtIndex < 0)
|
||||
subExtIndex = 0;
|
||||
defaultItemName = GetDefaultName2(fileName,
|
||||
format.Exts[subExtIndex].Ext,
|
||||
format.Exts[subExtIndex].AddExt);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
if (badResult != S_OK)
|
||||
return badResult;
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
HRESULT OpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &filePath,
|
||||
IInArchive **archiveResult,
|
||||
int &formatIndex,
|
||||
UString &defaultItemName,
|
||||
IArchiveOpenCallback *openArchiveCallback)
|
||||
{
|
||||
CInFileStream *inStreamSpec = new CInFileStream;
|
||||
CMyComPtr<IInStream> inStream(inStreamSpec);
|
||||
if (!inStreamSpec->Open(filePath))
|
||||
return GetLastError();
|
||||
return OpenArchive(codecs, inStream, ExtractFileNameFromPath(filePath),
|
||||
archiveResult, formatIndex,
|
||||
defaultItemName, openArchiveCallback);
|
||||
}
|
||||
|
||||
static void MakeDefaultName(UString &name)
|
||||
{
|
||||
int dotPos = name.ReverseFind(L'.');
|
||||
if (dotPos < 0)
|
||||
return;
|
||||
UString ext = name.Mid(dotPos + 1);
|
||||
if (ext.IsEmpty())
|
||||
return;
|
||||
for (int pos = 0; pos < ext.Length(); pos++)
|
||||
if (ext[pos] < L'0' || ext[pos] > L'9')
|
||||
return;
|
||||
name = name.Left(dotPos);
|
||||
}
|
||||
|
||||
HRESULT OpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &fileName,
|
||||
IInArchive **archive0,
|
||||
IInArchive **archive1,
|
||||
int &formatIndex0,
|
||||
int &formatIndex1,
|
||||
UString &defaultItemName0,
|
||||
UString &defaultItemName1,
|
||||
IArchiveOpenCallback *openArchiveCallback)
|
||||
{
|
||||
HRESULT result = OpenArchive(codecs, fileName,
|
||||
archive0, formatIndex0, defaultItemName0, openArchiveCallback);
|
||||
RINOK(result);
|
||||
CMyComPtr<IInArchiveGetStream> getStream;
|
||||
result = (*archive0)->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream);
|
||||
if (result != S_OK || getStream == 0)
|
||||
return S_OK;
|
||||
|
||||
CMyComPtr<ISequentialInStream> subSeqStream;
|
||||
result = getStream->GetStream(0, &subSeqStream);
|
||||
if (result != S_OK)
|
||||
return S_OK;
|
||||
|
||||
CMyComPtr<IInStream> subStream;
|
||||
if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK)
|
||||
return S_OK;
|
||||
if (!subStream)
|
||||
return S_OK;
|
||||
|
||||
UInt32 numItems;
|
||||
RINOK((*archive0)->GetNumberOfItems(&numItems));
|
||||
if (numItems < 1)
|
||||
return S_OK;
|
||||
|
||||
UString subPath;
|
||||
RINOK(GetArchiveItemPath(*archive0, 0, subPath))
|
||||
if (subPath.IsEmpty())
|
||||
{
|
||||
MakeDefaultName(defaultItemName0);
|
||||
subPath = defaultItemName0;
|
||||
const CArcInfoEx &format = codecs->Formats[formatIndex0];
|
||||
if (format.Name.CompareNoCase(L"7z") == 0)
|
||||
{
|
||||
if (subPath.Right(3).CompareNoCase(L".7z") != 0)
|
||||
subPath += L".7z";
|
||||
}
|
||||
}
|
||||
else
|
||||
subPath = ExtractFileNameFromPath(subPath);
|
||||
|
||||
CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
|
||||
openArchiveCallback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
|
||||
if (setSubArchiveName)
|
||||
setSubArchiveName->SetSubArchiveName(subPath);
|
||||
|
||||
result = OpenArchive(codecs, subStream, subPath,
|
||||
archive1, formatIndex1, defaultItemName1, openArchiveCallback);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static void SetCallback(const UString &archiveName,
|
||||
IOpenCallbackUI *openCallbackUI, CMyComPtr<IArchiveOpenCallback> &openCallback)
|
||||
{
|
||||
COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
|
||||
openCallback = openCallbackSpec;
|
||||
openCallbackSpec->Callback = openCallbackUI;
|
||||
|
||||
UString fullName;
|
||||
int fileNamePartStartIndex;
|
||||
NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
|
||||
openCallbackSpec->Init(
|
||||
fullName.Left(fileNamePartStartIndex),
|
||||
fullName.Mid(fileNamePartStartIndex));
|
||||
}
|
||||
|
||||
HRESULT MyOpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &archiveName,
|
||||
IInArchive **archive, UString &defaultItemName, IOpenCallbackUI *openCallbackUI)
|
||||
{
|
||||
CMyComPtr<IArchiveOpenCallback> openCallback;
|
||||
SetCallback(archiveName, openCallbackUI, openCallback);
|
||||
int formatInfo;
|
||||
return OpenArchive(codecs, archiveName, archive, formatInfo, defaultItemName, openCallback);
|
||||
}
|
||||
|
||||
HRESULT MyOpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &archiveName,
|
||||
IInArchive **archive0,
|
||||
IInArchive **archive1,
|
||||
UString &defaultItemName0,
|
||||
UString &defaultItemName1,
|
||||
UStringVector &volumePaths,
|
||||
UInt64 &volumesSize,
|
||||
IOpenCallbackUI *openCallbackUI)
|
||||
{
|
||||
volumesSize = 0;
|
||||
COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
|
||||
CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
|
||||
openCallbackSpec->Callback = openCallbackUI;
|
||||
|
||||
UString fullName;
|
||||
int fileNamePartStartIndex;
|
||||
NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
|
||||
UString prefix = fullName.Left(fileNamePartStartIndex);
|
||||
UString name = fullName.Mid(fileNamePartStartIndex);
|
||||
openCallbackSpec->Init(prefix, name);
|
||||
|
||||
int formatIndex0, formatIndex1;
|
||||
RINOK(OpenArchive(codecs, archiveName,
|
||||
archive0,
|
||||
archive1,
|
||||
formatIndex0,
|
||||
formatIndex1,
|
||||
defaultItemName0,
|
||||
defaultItemName1,
|
||||
openCallback));
|
||||
volumePaths.Add(prefix + name);
|
||||
for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++)
|
||||
volumePaths.Add(prefix + openCallbackSpec->FileNames[i]);
|
||||
volumesSize = openCallbackSpec->TotalSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CArchiveLink::Close()
|
||||
{
|
||||
if (Archive1 != 0)
|
||||
RINOK(Archive1->Close());
|
||||
if (Archive0 != 0)
|
||||
RINOK(Archive0->Close());
|
||||
IsOpen = false;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void CArchiveLink::Release()
|
||||
{
|
||||
IsOpen = false;
|
||||
Archive1.Release();
|
||||
Archive0.Release();
|
||||
}
|
||||
|
||||
HRESULT OpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &archiveName,
|
||||
CArchiveLink &archiveLink,
|
||||
IArchiveOpenCallback *openCallback)
|
||||
{
|
||||
HRESULT res = OpenArchive(codecs, archiveName,
|
||||
&archiveLink.Archive0, &archiveLink.Archive1,
|
||||
archiveLink.FormatIndex0, archiveLink.FormatIndex1,
|
||||
archiveLink.DefaultItemName0, archiveLink.DefaultItemName1,
|
||||
openCallback);
|
||||
archiveLink.IsOpen = (res == S_OK);
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT MyOpenArchive(CCodecs *codecs,
|
||||
const UString &archiveName,
|
||||
CArchiveLink &archiveLink,
|
||||
IOpenCallbackUI *openCallbackUI)
|
||||
{
|
||||
HRESULT res = MyOpenArchive(codecs, archiveName,
|
||||
&archiveLink.Archive0, &archiveLink.Archive1,
|
||||
archiveLink.DefaultItemName0, archiveLink.DefaultItemName1,
|
||||
archiveLink.VolumePaths,
|
||||
archiveLink.VolumesSize,
|
||||
openCallbackUI);
|
||||
archiveLink.IsOpen = (res == S_OK);
|
||||
return res;
|
||||
}
|
||||
|
||||
HRESULT ReOpenArchive(CCodecs *codecs, CArchiveLink &archiveLink, const UString &fileName)
|
||||
{
|
||||
if (archiveLink.GetNumLevels() > 1)
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (archiveLink.GetNumLevels() == 0)
|
||||
return MyOpenArchive(codecs, fileName, archiveLink, 0);
|
||||
|
||||
CMyComPtr<IArchiveOpenCallback> openCallback;
|
||||
SetCallback(fileName, NULL, openCallback);
|
||||
|
||||
HRESULT res = ReOpenArchive(archiveLink.GetArchive(), fileName, openCallback);
|
||||
archiveLink.IsOpen = (res == S_OK);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// OpenArchive.h
|
||||
|
||||
#ifndef __OPENARCHIVE_H
|
||||
#define __OPENARCHIVE_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
#include "Windows/FileFind.h"
|
||||
|
||||
#include "../../Archive/IArchive.h"
|
||||
#include "LoadCodecs.h"
|
||||
#include "ArchiveOpenCallback.h"
|
||||
|
||||
HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result);
|
||||
HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result);
|
||||
HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index,
|
||||
const FILETIME &defaultFileTime, FILETIME &fileTime);
|
||||
HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result);
|
||||
HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result);
|
||||
HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result);
|
||||
|
||||
struct ISetSubArchiveName
|
||||
{
|
||||
virtual void SetSubArchiveName(const wchar_t *name) = 0;
|
||||
};
|
||||
|
||||
HRESULT OpenArchive(
|
||||
CCodecs *codecs,
|
||||
IInStream *inStream,
|
||||
const UString &fileName,
|
||||
IInArchive **archiveResult,
|
||||
int &formatIndex,
|
||||
UString &defaultItemName,
|
||||
IArchiveOpenCallback *openArchiveCallback);
|
||||
|
||||
HRESULT OpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &filePath,
|
||||
IInArchive **archive,
|
||||
int &formatIndex,
|
||||
UString &defaultItemName,
|
||||
IArchiveOpenCallback *openArchiveCallback);
|
||||
|
||||
HRESULT OpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &filePath,
|
||||
IInArchive **archive0,
|
||||
IInArchive **archive1,
|
||||
int &formatIndex0,
|
||||
int &formatIndex1,
|
||||
UString &defaultItemName0,
|
||||
UString &defaultItemName1,
|
||||
IArchiveOpenCallback *openArchiveCallback);
|
||||
|
||||
|
||||
HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName, IArchiveOpenCallback *openArchiveCallback);
|
||||
|
||||
HRESULT MyOpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &archiveName,
|
||||
IInArchive **archive,
|
||||
UString &defaultItemName,
|
||||
IOpenCallbackUI *openCallbackUI);
|
||||
|
||||
HRESULT MyOpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &archiveName,
|
||||
IInArchive **archive0,
|
||||
IInArchive **archive1,
|
||||
UString &defaultItemName0,
|
||||
UString &defaultItemName1,
|
||||
UStringVector &volumePaths,
|
||||
UInt64 &volumesSize,
|
||||
IOpenCallbackUI *openCallbackUI);
|
||||
|
||||
struct CArchiveLink
|
||||
{
|
||||
CMyComPtr<IInArchive> Archive0;
|
||||
CMyComPtr<IInArchive> Archive1;
|
||||
UString DefaultItemName0;
|
||||
UString DefaultItemName1;
|
||||
|
||||
int FormatIndex0;
|
||||
int FormatIndex1;
|
||||
|
||||
UStringVector VolumePaths;
|
||||
|
||||
UInt64 VolumesSize;
|
||||
|
||||
int GetNumLevels() const
|
||||
{
|
||||
int result = 0;
|
||||
if (Archive0)
|
||||
{
|
||||
result++;
|
||||
if (Archive1)
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsOpen;
|
||||
|
||||
CArchiveLink(): IsOpen(false), VolumesSize(0) {};
|
||||
|
||||
IInArchive *GetArchive() { return Archive1 != 0 ? Archive1: Archive0; }
|
||||
UString GetDefaultItemName() { return Archive1 != 0 ? DefaultItemName1: DefaultItemName0; }
|
||||
int GetArchiverIndex() const { return Archive1 != 0 ? FormatIndex1: FormatIndex0; }
|
||||
HRESULT Close();
|
||||
void Release();
|
||||
};
|
||||
|
||||
HRESULT OpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &archiveName,
|
||||
CArchiveLink &archiveLink,
|
||||
IArchiveOpenCallback *openCallback);
|
||||
|
||||
HRESULT MyOpenArchive(
|
||||
CCodecs *codecs,
|
||||
const UString &archiveName,
|
||||
CArchiveLink &archiveLink,
|
||||
IOpenCallbackUI *openCallbackUI);
|
||||
|
||||
HRESULT ReOpenArchive(
|
||||
CCodecs *codecs,
|
||||
CArchiveLink &archiveLink,
|
||||
const UString &fileName);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// PropIDUtils.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "PropIDUtils.h"
|
||||
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/StringConvert.h"
|
||||
|
||||
#include "Windows/FileFind.h"
|
||||
#include "Windows/PropVariantConversions.h"
|
||||
|
||||
#include "../../PropID.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
static UString ConvertUInt32ToString(UInt32 value)
|
||||
{
|
||||
wchar_t buffer[32];
|
||||
ConvertUInt64ToString(value, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void ConvertUInt32ToHex(UInt32 value, wchar_t *s)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
int t = value & 0xF;
|
||||
value >>= 4;
|
||||
s[7 - i] = (wchar_t)((t < 10) ? (L'0' + t) : (L'A' + (t - 10)));
|
||||
}
|
||||
s[8] = L'\0';
|
||||
}
|
||||
|
||||
UString ConvertPropertyToString(const PROPVARIANT &propVariant, PROPID propID, bool full)
|
||||
{
|
||||
switch(propID)
|
||||
{
|
||||
case kpidCreationTime:
|
||||
case kpidLastWriteTime:
|
||||
case kpidLastAccessTime:
|
||||
{
|
||||
if (propVariant.vt != VT_FILETIME)
|
||||
return UString(); // It is error;
|
||||
FILETIME localFileTime;
|
||||
if (propVariant.filetime.dwHighDateTime == 0 &&
|
||||
propVariant.filetime.dwLowDateTime == 0)
|
||||
return UString();
|
||||
if (!::FileTimeToLocalFileTime(&propVariant.filetime, &localFileTime))
|
||||
return UString(); // It is error;
|
||||
return ConvertFileTimeToString(localFileTime, true, full);
|
||||
}
|
||||
case kpidCRC:
|
||||
{
|
||||
if(propVariant.vt != VT_UI4)
|
||||
break;
|
||||
wchar_t temp[12];
|
||||
ConvertUInt32ToHex(propVariant.ulVal, temp);
|
||||
return temp;
|
||||
}
|
||||
case kpidAttributes:
|
||||
{
|
||||
if(propVariant.vt != VT_UI4)
|
||||
break;
|
||||
UString result;
|
||||
UInt32 attributes = propVariant.ulVal;
|
||||
if (NFile::NFind::NAttributes::IsReadOnly(attributes)) result += L'R';
|
||||
if (NFile::NFind::NAttributes::IsHidden(attributes)) result += L'H';
|
||||
if (NFile::NFind::NAttributes::IsSystem(attributes)) result += L'S';
|
||||
if (NFile::NFind::NAttributes::IsDirectory(attributes)) result += L'D';
|
||||
if (NFile::NFind::NAttributes::IsArchived(attributes)) result += L'A';
|
||||
if (NFile::NFind::NAttributes::IsCompressed(attributes)) result += L'C';
|
||||
if (NFile::NFind::NAttributes::IsEncrypted(attributes)) result += L'E';
|
||||
return result;
|
||||
}
|
||||
case kpidDictionarySize:
|
||||
{
|
||||
if(propVariant.vt != VT_UI4)
|
||||
break;
|
||||
UInt32 size = propVariant.ulVal;
|
||||
if (size % (1 << 20) == 0)
|
||||
return ConvertUInt32ToString(size >> 20) + L"MB";
|
||||
if (size % (1 << 10) == 0)
|
||||
return ConvertUInt32ToString(size >> 10) + L"KB";
|
||||
return ConvertUInt32ToString(size);
|
||||
}
|
||||
}
|
||||
return ConvertPropVariantToString(propVariant);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// PropIDUtils.h
|
||||
|
||||
#ifndef __PROPIDUTILS_H
|
||||
#define __PROPIDUTILS_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
|
||||
UString ConvertPropertyToString(const PROPVARIANT &propVariant, PROPID propID, bool full = true);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
// Property.h
|
||||
|
||||
#ifndef __PROPERTY_H
|
||||
#define __PROPERTY_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
|
||||
struct CProperty
|
||||
{
|
||||
UString Name;
|
||||
UString Value;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
// SetProperties.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "SetProperties.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Common/MyString.h"
|
||||
#include "Common/StringToInt.h"
|
||||
#include "Common/MyCom.h"
|
||||
|
||||
#include "../../Archive/IArchive.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NCOM;
|
||||
|
||||
static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
|
||||
{
|
||||
const wchar_t *endPtr;
|
||||
UInt64 result = ConvertStringToUInt64(s, &endPtr);
|
||||
if (endPtr - (const wchar_t *)s != s.Length())
|
||||
prop = s;
|
||||
else if (result <= 0xFFFFFFFF)
|
||||
prop = (UInt32)result;
|
||||
else
|
||||
prop = result;
|
||||
}
|
||||
|
||||
HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
|
||||
{
|
||||
if (properties.IsEmpty())
|
||||
return S_OK;
|
||||
CMyComPtr<ISetProperties> setProperties;
|
||||
unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties);
|
||||
if (!setProperties)
|
||||
return S_OK;
|
||||
|
||||
UStringVector realNames;
|
||||
CPropVariant *values = new CPropVariant[properties.Size()];
|
||||
try
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < properties.Size(); i++)
|
||||
{
|
||||
const CProperty &property = properties[i];
|
||||
NCOM::CPropVariant propVariant;
|
||||
if (!property.Value.IsEmpty())
|
||||
ParseNumberString(property.Value, propVariant);
|
||||
realNames.Add(property.Name);
|
||||
values[i] = propVariant;
|
||||
}
|
||||
CRecordVector<const wchar_t *> names;
|
||||
for(i = 0; i < realNames.Size(); i++)
|
||||
names.Add((const wchar_t *)realNames[i]);
|
||||
|
||||
RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
delete []values;
|
||||
throw;
|
||||
}
|
||||
delete []values;
|
||||
return S_OK;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// SetProperties.h
|
||||
|
||||
#ifndef __SETPROPERTIES_H
|
||||
#define __SETPROPERTIES_H
|
||||
|
||||
#include "Property.h"
|
||||
|
||||
HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// SortUtils.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "SortUtils.h"
|
||||
#include "Common/Wildcard.h"
|
||||
|
||||
static int CompareStrings(const int *p1, const int *p2, void *param)
|
||||
{
|
||||
const UStringVector &strings = *(const UStringVector *)param;
|
||||
return CompareFileNames(strings[*p1], strings[*p2]);
|
||||
}
|
||||
|
||||
void SortFileNames(const UStringVector &strings, CIntVector &indices)
|
||||
{
|
||||
indices.Clear();
|
||||
int numItems = strings.Size();
|
||||
indices.Reserve(numItems);
|
||||
for(int i = 0; i < numItems; i++)
|
||||
indices.Add(i);
|
||||
indices.Sort(CompareStrings, (void *)&strings);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// SortUtils.h
|
||||
|
||||
#ifndef __SORTUTLS_H
|
||||
#define __SORTUTLS_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
|
||||
void SortFileNames(const UStringVector &strings, CIntVector &indices);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
// TempFiles.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "TempFiles.h"
|
||||
|
||||
#include "Windows/FileDir.h"
|
||||
#include "Windows/FileIO.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NFile;
|
||||
|
||||
void CTempFiles::Clear()
|
||||
{
|
||||
while(!Paths.IsEmpty())
|
||||
{
|
||||
NDirectory::DeleteFileAlways((LPCWSTR)Paths.Back());
|
||||
Paths.DeleteBack();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// TempFiles.h
|
||||
|
||||
#ifndef __TEMPFILES_H
|
||||
#define __TEMPFILES_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
|
||||
class CTempFiles
|
||||
{
|
||||
void Clear();
|
||||
public:
|
||||
UStringVector Paths;
|
||||
~CTempFiles() { Clear(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,852 @@
|
||||
// Update.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <mapi.h>
|
||||
#endif
|
||||
|
||||
#include "Update.h"
|
||||
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/CommandLineParser.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Windows/DLL.h"
|
||||
#endif
|
||||
|
||||
#include "Windows/Defs.h"
|
||||
#include "Windows/FileDir.h"
|
||||
#include "Windows/FileFind.h"
|
||||
#include "Windows/FileName.h"
|
||||
#include "Windows/PropVariant.h"
|
||||
#include "Windows/PropVariantConversions.h"
|
||||
// #include "Windows/Synchronization.h"
|
||||
|
||||
#include "../../Common/FileStreams.h"
|
||||
#include "../../Compress/Copy/CopyCoder.h"
|
||||
|
||||
#include "../Common/DirItem.h"
|
||||
#include "../Common/EnumDirItems.h"
|
||||
#include "../Common/UpdateProduce.h"
|
||||
#include "../Common/OpenArchive.h"
|
||||
|
||||
#include "TempFiles.h"
|
||||
#include "UpdateCallback.h"
|
||||
#include "EnumDirItems.h"
|
||||
#include "SetProperties.h"
|
||||
|
||||
static const char *kUpdateIsNotSupoorted =
|
||||
"update operations are not supported for this archive";
|
||||
|
||||
using namespace NCommandLineParser;
|
||||
using namespace NWindows;
|
||||
using namespace NCOM;
|
||||
using namespace NFile;
|
||||
using namespace NName;
|
||||
|
||||
static const wchar_t *kTempFolderPrefix = L"7zE";
|
||||
|
||||
using namespace NUpdateArchive;
|
||||
|
||||
static HRESULT CopyBlock(ISequentialInStream *inStream, ISequentialOutStream *outStream)
|
||||
{
|
||||
CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
|
||||
return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
class COutMultiVolStream:
|
||||
public IOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
int _streamIndex; // required stream
|
||||
UInt64 _offsetPos; // offset from start of _streamIndex index
|
||||
UInt64 _absPos;
|
||||
UInt64 _length;
|
||||
|
||||
struct CSubStreamInfo
|
||||
{
|
||||
COutFileStream *StreamSpec;
|
||||
CMyComPtr<IOutStream> Stream;
|
||||
UString Name;
|
||||
UInt64 Pos;
|
||||
UInt64 RealSize;
|
||||
};
|
||||
CObjectVector<CSubStreamInfo> Streams;
|
||||
public:
|
||||
// CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
|
||||
CRecordVector<UInt64> Sizes;
|
||||
UString Prefix;
|
||||
CTempFiles *TempFiles;
|
||||
|
||||
void Init()
|
||||
{
|
||||
_streamIndex = 0;
|
||||
_offsetPos = 0;
|
||||
_absPos = 0;
|
||||
_length = 0;
|
||||
}
|
||||
|
||||
HRESULT Close();
|
||||
|
||||
MY_UNKNOWN_IMP1(IOutStream)
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
|
||||
STDMETHOD(SetSize)(Int64 newSize);
|
||||
};
|
||||
|
||||
// static NSynchronization::CCriticalSection g_TempPathsCS;
|
||||
|
||||
HRESULT COutMultiVolStream::Close()
|
||||
{
|
||||
HRESULT res = S_OK;
|
||||
for (int i = 0; i < Streams.Size(); i++)
|
||||
{
|
||||
CSubStreamInfo &s = Streams[i];
|
||||
if (s.StreamSpec)
|
||||
{
|
||||
HRESULT res2 = s.StreamSpec->Close();
|
||||
if (res2 != S_OK)
|
||||
res = res2;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
if(processedSize != NULL)
|
||||
*processedSize = 0;
|
||||
while(size > 0)
|
||||
{
|
||||
if (_streamIndex >= Streams.Size())
|
||||
{
|
||||
CSubStreamInfo subStream;
|
||||
|
||||
wchar_t temp[32];
|
||||
ConvertUInt64ToString(_streamIndex + 1, temp);
|
||||
UString res = temp;
|
||||
while (res.Length() < 3)
|
||||
res = UString(L'0') + res;
|
||||
UString name = Prefix + res;
|
||||
subStream.StreamSpec = new COutFileStream;
|
||||
subStream.Stream = subStream.StreamSpec;
|
||||
if(!subStream.StreamSpec->Create(name, false))
|
||||
return ::GetLastError();
|
||||
{
|
||||
// NSynchronization::CCriticalSectionLock lock(g_TempPathsCS);
|
||||
TempFiles->Paths.Add(name);
|
||||
}
|
||||
|
||||
subStream.Pos = 0;
|
||||
subStream.RealSize = 0;
|
||||
subStream.Name = name;
|
||||
Streams.Add(subStream);
|
||||
continue;
|
||||
}
|
||||
CSubStreamInfo &subStream = Streams[_streamIndex];
|
||||
|
||||
int index = _streamIndex;
|
||||
if (index >= Sizes.Size())
|
||||
index = Sizes.Size() - 1;
|
||||
UInt64 volSize = Sizes[index];
|
||||
|
||||
if (_offsetPos >= volSize)
|
||||
{
|
||||
_offsetPos -= volSize;
|
||||
_streamIndex++;
|
||||
continue;
|
||||
}
|
||||
if (_offsetPos != subStream.Pos)
|
||||
{
|
||||
// CMyComPtr<IOutStream> outStream;
|
||||
// RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
|
||||
RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
|
||||
subStream.Pos = _offsetPos;
|
||||
}
|
||||
|
||||
UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos);
|
||||
UInt32 realProcessed;
|
||||
RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
|
||||
data = (void *)((Byte *)data + realProcessed);
|
||||
size -= realProcessed;
|
||||
subStream.Pos += realProcessed;
|
||||
_offsetPos += realProcessed;
|
||||
_absPos += realProcessed;
|
||||
if (_absPos > _length)
|
||||
_length = _absPos;
|
||||
if (_offsetPos > subStream.RealSize)
|
||||
subStream.RealSize = _offsetPos;
|
||||
if(processedSize != NULL)
|
||||
*processedSize += realProcessed;
|
||||
if (subStream.Pos == volSize)
|
||||
{
|
||||
_streamIndex++;
|
||||
_offsetPos = 0;
|
||||
}
|
||||
if (realProcessed == 0 && curSize != 0)
|
||||
return E_FAIL;
|
||||
break;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
|
||||
{
|
||||
if(seekOrigin >= 3)
|
||||
return STG_E_INVALIDFUNCTION;
|
||||
switch(seekOrigin)
|
||||
{
|
||||
case STREAM_SEEK_SET:
|
||||
_absPos = offset;
|
||||
break;
|
||||
case STREAM_SEEK_CUR:
|
||||
_absPos += offset;
|
||||
break;
|
||||
case STREAM_SEEK_END:
|
||||
_absPos = _length + offset;
|
||||
break;
|
||||
}
|
||||
_offsetPos = _absPos;
|
||||
if (newPosition != NULL)
|
||||
*newPosition = _absPos;
|
||||
_streamIndex = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP COutMultiVolStream::SetSize(Int64 newSize)
|
||||
{
|
||||
if (newSize < 0)
|
||||
return E_INVALIDARG;
|
||||
int i = 0;
|
||||
while (i < Streams.Size())
|
||||
{
|
||||
CSubStreamInfo &subStream = Streams[i++];
|
||||
if ((UInt64)newSize < subStream.RealSize)
|
||||
{
|
||||
RINOK(subStream.Stream->SetSize(newSize));
|
||||
subStream.RealSize = newSize;
|
||||
break;
|
||||
}
|
||||
newSize -= subStream.RealSize;
|
||||
}
|
||||
while (i < Streams.Size())
|
||||
{
|
||||
{
|
||||
CSubStreamInfo &subStream = Streams.Back();
|
||||
subStream.Stream.Release();
|
||||
NDirectory::DeleteFileAlways(subStream.Name);
|
||||
}
|
||||
Streams.DeleteBack();
|
||||
}
|
||||
_offsetPos = _absPos;
|
||||
_streamIndex = 0;
|
||||
_length = newSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const wchar_t *kDefaultArchiveType = L"7z";
|
||||
static const wchar_t *kSFXExtension =
|
||||
#ifdef _WIN32
|
||||
L"exe";
|
||||
#else
|
||||
L"";
|
||||
#endif
|
||||
|
||||
bool CUpdateOptions::Init(const CCodecs *codecs, const UString &arcPath, const UString &arcType)
|
||||
{
|
||||
if (!arcType.IsEmpty())
|
||||
MethodMode.FormatIndex = codecs->FindFormatForArchiveType(arcType);
|
||||
else
|
||||
{
|
||||
MethodMode.FormatIndex = codecs->FindFormatForArchiveName(arcPath);
|
||||
if (MethodMode.FormatIndex < 0)
|
||||
MethodMode.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArchiveType);
|
||||
}
|
||||
if (MethodMode.FormatIndex < 0)
|
||||
return false;
|
||||
const CArcInfoEx &arcInfo = codecs->Formats[MethodMode.FormatIndex];
|
||||
UString typeExt = arcInfo.GetMainExt();
|
||||
UString ext = typeExt;
|
||||
if (SfxMode)
|
||||
ext = kSFXExtension;
|
||||
ArchivePath.BaseExtension = ext;
|
||||
ArchivePath.VolExtension = typeExt;
|
||||
ArchivePath.ParseFromPath(arcPath);
|
||||
for (int i = 0; i < Commands.Size(); i++)
|
||||
{
|
||||
CUpdateArchiveCommand &uc = Commands[i];
|
||||
uc.ArchivePath.BaseExtension = ext;
|
||||
uc.ArchivePath.VolExtension = typeExt;
|
||||
uc.ArchivePath.ParseFromPath(uc.UserArchivePath);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static HRESULT Compress(
|
||||
CCodecs *codecs,
|
||||
const CActionSet &actionSet,
|
||||
IInArchive *archive,
|
||||
const CCompressionMethodMode &compressionMethod,
|
||||
CArchivePath &archivePath,
|
||||
const CObjectVector<CArchiveItem> &archiveItems,
|
||||
bool shareForWrite,
|
||||
bool stdInMode,
|
||||
/* const UString & stdInFileName, */
|
||||
bool stdOutMode,
|
||||
const CObjectVector<CDirItem> &dirItems,
|
||||
bool sfxMode,
|
||||
const UString &sfxModule,
|
||||
const CRecordVector<UInt64> &volumesSizes,
|
||||
CTempFiles &tempFiles,
|
||||
CUpdateErrorInfo &errorInfo,
|
||||
IUpdateCallbackUI *callback)
|
||||
{
|
||||
CMyComPtr<IOutArchive> outArchive;
|
||||
if(archive != NULL)
|
||||
{
|
||||
CMyComPtr<IInArchive> archive2 = archive;
|
||||
HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
|
||||
if(result != S_OK)
|
||||
throw kUpdateIsNotSupoorted;
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(codecs->CreateOutArchive(compressionMethod.FormatIndex, outArchive));
|
||||
|
||||
#ifdef EXTERNAL_CODECS
|
||||
{
|
||||
CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
|
||||
outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
|
||||
if (setCompressCodecsInfo)
|
||||
{
|
||||
RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (outArchive == 0)
|
||||
throw kUpdateIsNotSupoorted;
|
||||
|
||||
NFileTimeType::EEnum fileTimeType;
|
||||
UInt32 value;
|
||||
RINOK(outArchive->GetFileTimeType(&value));
|
||||
|
||||
switch(value)
|
||||
{
|
||||
case NFileTimeType::kWindows:
|
||||
case NFileTimeType::kDOS:
|
||||
case NFileTimeType::kUnix:
|
||||
fileTimeType = NFileTimeType::EEnum(value);
|
||||
break;
|
||||
default:
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
CObjectVector<CUpdatePair> updatePairs;
|
||||
GetUpdatePairInfoList(dirItems, archiveItems, fileTimeType, updatePairs); // must be done only once!!!
|
||||
|
||||
CObjectVector<CUpdatePair2> updatePairs2;
|
||||
UpdateProduce(updatePairs, actionSet, updatePairs2);
|
||||
|
||||
UInt32 numFiles = 0;
|
||||
for (int i = 0; i < updatePairs2.Size(); i++)
|
||||
if (updatePairs2[i].NewData)
|
||||
numFiles++;
|
||||
|
||||
RINOK(callback->SetNumFiles(numFiles));
|
||||
|
||||
|
||||
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
|
||||
CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
|
||||
|
||||
updateCallbackSpec->ShareForWrite = shareForWrite;
|
||||
updateCallbackSpec->StdInMode = stdInMode;
|
||||
updateCallbackSpec->Callback = callback;
|
||||
updateCallbackSpec->DirItems = &dirItems;
|
||||
updateCallbackSpec->ArchiveItems = &archiveItems;
|
||||
updateCallbackSpec->UpdatePairs = &updatePairs2;
|
||||
|
||||
CMyComPtr<ISequentialOutStream> outStream;
|
||||
|
||||
const UString &archiveName = archivePath.GetFinalPath();
|
||||
if (!stdOutMode)
|
||||
{
|
||||
UString resultPath;
|
||||
int pos;
|
||||
if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos))
|
||||
throw 1417161;
|
||||
NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
|
||||
}
|
||||
|
||||
COutFileStream *outStreamSpec = NULL;
|
||||
COutMultiVolStream *volStreamSpec = NULL;
|
||||
|
||||
if (volumesSizes.Size() == 0)
|
||||
{
|
||||
if (stdOutMode)
|
||||
outStream = new CStdOutFileStream;
|
||||
else
|
||||
{
|
||||
outStreamSpec = new COutFileStream;
|
||||
outStream = outStreamSpec;
|
||||
bool isOK = false;
|
||||
UString realPath;
|
||||
for (int i = 0; i < (1 << 16); i++)
|
||||
{
|
||||
if (archivePath.Temp)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
wchar_t s[32];
|
||||
ConvertUInt64ToString(i, s);
|
||||
archivePath.TempPostfix = s;
|
||||
}
|
||||
realPath = archivePath.GetTempPath();
|
||||
}
|
||||
else
|
||||
realPath = archivePath.GetFinalPath();
|
||||
if (outStreamSpec->Create(realPath, false))
|
||||
{
|
||||
tempFiles.Paths.Add(realPath);
|
||||
isOK = true;
|
||||
break;
|
||||
}
|
||||
if (::GetLastError() != ERROR_FILE_EXISTS)
|
||||
break;
|
||||
if (!archivePath.Temp)
|
||||
break;
|
||||
}
|
||||
if (!isOK)
|
||||
{
|
||||
errorInfo.SystemError = ::GetLastError();
|
||||
errorInfo.FileName = realPath;
|
||||
errorInfo.Message = L"Can not open file";
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stdOutMode)
|
||||
return E_FAIL;
|
||||
volStreamSpec = new COutMultiVolStream;
|
||||
outStream = volStreamSpec;
|
||||
volStreamSpec->Sizes = volumesSizes;
|
||||
volStreamSpec->Prefix = archivePath.GetFinalPath() + UString(L".");
|
||||
volStreamSpec->TempFiles = &tempFiles;
|
||||
volStreamSpec->Init();
|
||||
|
||||
/*
|
||||
updateCallbackSpec->VolumesSizes = volumesSizes;
|
||||
updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
|
||||
if (!archivePath.VolExtension.IsEmpty())
|
||||
updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension;
|
||||
*/
|
||||
}
|
||||
|
||||
RINOK(SetProperties(outArchive, compressionMethod.Properties));
|
||||
|
||||
if (sfxMode)
|
||||
{
|
||||
CInFileStream *sfxStreamSpec = new CInFileStream;
|
||||
CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
|
||||
if (!sfxStreamSpec->Open(sfxModule))
|
||||
{
|
||||
errorInfo.SystemError = ::GetLastError();
|
||||
errorInfo.Message = L"Can't open sfx module";
|
||||
errorInfo.FileName = sfxModule;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
CMyComPtr<ISequentialOutStream> sfxOutStream;
|
||||
COutFileStream *outStreamSpec = NULL;
|
||||
if (volumesSizes.Size() == 0)
|
||||
sfxOutStream = outStream;
|
||||
else
|
||||
{
|
||||
outStreamSpec = new COutFileStream;
|
||||
sfxOutStream = outStreamSpec;
|
||||
UString realPath = archivePath.GetFinalPath();
|
||||
if (!outStreamSpec->Create(realPath, false))
|
||||
{
|
||||
errorInfo.SystemError = ::GetLastError();
|
||||
errorInfo.FileName = realPath;
|
||||
errorInfo.Message = L"Can not open file";
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
RINOK(CopyBlock(sfxStream, sfxOutStream));
|
||||
if (outStreamSpec)
|
||||
{
|
||||
RINOK(outStreamSpec->Close());
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(), updateCallback);
|
||||
callback->Finilize();
|
||||
RINOK(result);
|
||||
if (outStreamSpec)
|
||||
result = outStreamSpec->Close();
|
||||
else if (volStreamSpec)
|
||||
result = volStreamSpec->Close();
|
||||
return result;
|
||||
}
|
||||
|
||||
HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor,
|
||||
IInArchive *archive,
|
||||
const UString &defaultItemName,
|
||||
const NWindows::NFile::NFind::CFileInfoW &archiveFileInfo,
|
||||
CObjectVector<CArchiveItem> &archiveItems)
|
||||
{
|
||||
archiveItems.Clear();
|
||||
UInt32 numItems;
|
||||
RINOK(archive->GetNumberOfItems(&numItems));
|
||||
archiveItems.Reserve(numItems);
|
||||
for(UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
CArchiveItem ai;
|
||||
|
||||
RINOK(GetArchiveItemPath(archive, i, ai.Name));
|
||||
RINOK(IsArchiveItemFolder(archive, i, ai.IsDirectory));
|
||||
ai.Censored = censor.CheckPath(ai.Name.IsEmpty() ? defaultItemName : ai.Name, !ai.IsDirectory);
|
||||
RINOK(GetArchiveItemFileTime(archive, i,
|
||||
archiveFileInfo.LastWriteTime, ai.LastWriteTime));
|
||||
|
||||
CPropVariant propertySize;
|
||||
RINOK(archive->GetProperty(i, kpidSize, &propertySize));
|
||||
ai.SizeIsDefined = (propertySize.vt != VT_EMPTY);
|
||||
if (ai.SizeIsDefined)
|
||||
ai.Size = ConvertPropVariantToUInt64(propertySize);
|
||||
|
||||
ai.IndexInServer = i;
|
||||
archiveItems.Add(ai);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
static HRESULT UpdateWithItemLists(
|
||||
CCodecs *codecs,
|
||||
CUpdateOptions &options,
|
||||
IInArchive *archive,
|
||||
const CObjectVector<CArchiveItem> &archiveItems,
|
||||
const CObjectVector<CDirItem> &dirItems,
|
||||
CTempFiles &tempFiles,
|
||||
CUpdateErrorInfo &errorInfo,
|
||||
IUpdateCallbackUI2 *callback)
|
||||
{
|
||||
for(int i = 0; i < options.Commands.Size(); i++)
|
||||
{
|
||||
CUpdateArchiveCommand &command = options.Commands[i];
|
||||
if (options.StdOutMode)
|
||||
{
|
||||
RINOK(callback->StartArchive(0, archive != 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(),
|
||||
i == 0 && options.UpdateArchiveItself && archive != 0));
|
||||
}
|
||||
|
||||
RINOK(Compress(
|
||||
codecs,
|
||||
command.ActionSet, archive,
|
||||
options.MethodMode,
|
||||
command.ArchivePath,
|
||||
archiveItems,
|
||||
options.OpenShareForWrite,
|
||||
options.StdInMode,
|
||||
/* options.StdInFileName, */
|
||||
options.StdOutMode,
|
||||
dirItems,
|
||||
options.SfxMode, options.SfxModule,
|
||||
options.VolumesSizes,
|
||||
tempFiles,
|
||||
errorInfo, callback));
|
||||
|
||||
RINOK(callback->FinishArchive());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
class CCurrentDirRestorer
|
||||
{
|
||||
UString m_CurrentDirectory;
|
||||
public:
|
||||
CCurrentDirRestorer()
|
||||
{ NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); }
|
||||
~CCurrentDirRestorer()
|
||||
{ RestoreDirectory();}
|
||||
bool RestoreDirectory()
|
||||
{ return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(m_CurrentDirectory)); }
|
||||
};
|
||||
#endif
|
||||
|
||||
struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback
|
||||
{
|
||||
IUpdateCallbackUI2 *Callback;
|
||||
HRESULT CheckBreak() { return Callback->CheckBreak(); }
|
||||
};
|
||||
|
||||
HRESULT UpdateArchive(
|
||||
CCodecs *codecs,
|
||||
const NWildcard::CCensor &censor,
|
||||
CUpdateOptions &options,
|
||||
CUpdateErrorInfo &errorInfo,
|
||||
IOpenCallbackUI *openCallback,
|
||||
IUpdateCallbackUI2 *callback)
|
||||
{
|
||||
if (options.StdOutMode && options.EMailMode)
|
||||
return E_FAIL;
|
||||
|
||||
if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode))
|
||||
return E_NOTIMPL;
|
||||
|
||||
if (options.SfxMode)
|
||||
{
|
||||
CProperty property;
|
||||
property.Name = L"rsfx";
|
||||
property.Value = L"on";
|
||||
options.MethodMode.Properties.Add(property);
|
||||
if (options.SfxModule.IsEmpty())
|
||||
{
|
||||
errorInfo.Message = L"sfx file is not specified";
|
||||
return E_FAIL;
|
||||
}
|
||||
UString name = options.SfxModule;
|
||||
if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule))
|
||||
{
|
||||
errorInfo.Message = L"can't find specified sfx module";
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
const UString archiveName = options.ArchivePath.GetFinalPath();
|
||||
|
||||
UString defaultItemName;
|
||||
NFind::CFileInfoW archiveFileInfo;
|
||||
|
||||
CArchiveLink archiveLink;
|
||||
IInArchive *archive = 0;
|
||||
if (NFind::FindFile(archiveName, archiveFileInfo))
|
||||
{
|
||||
if (archiveFileInfo.IsDirectory())
|
||||
throw "there is no such archive";
|
||||
if (options.VolumesSizes.Size() > 0)
|
||||
return E_NOTIMPL;
|
||||
HRESULT result = MyOpenArchive(codecs, archiveName, archiveLink, openCallback);
|
||||
RINOK(callback->OpenResult(archiveName, result));
|
||||
RINOK(result);
|
||||
if (archiveLink.VolumePaths.Size() > 1)
|
||||
{
|
||||
errorInfo.SystemError = (DWORD)E_NOTIMPL;
|
||||
errorInfo.Message = L"Updating for multivolume archives is not implemented";
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
archive = archiveLink.GetArchive();
|
||||
defaultItemName = archiveLink.GetDefaultItemName();
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
if (archiveType.IsEmpty())
|
||||
throw "type of archive is not specified";
|
||||
*/
|
||||
}
|
||||
|
||||
CObjectVector<CDirItem> dirItems;
|
||||
if (options.StdInMode)
|
||||
{
|
||||
CDirItem item;
|
||||
item.FullPath = item.Name = options.StdInFileName;
|
||||
item.Size = (UInt64)(Int64)-1;
|
||||
item.Attributes = 0;
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
GetSystemTime(&st);
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
item.CreationTime = item.LastAccessTime = item.LastWriteTime = ft;
|
||||
dirItems.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool needScanning = false;
|
||||
for(int i = 0; i < options.Commands.Size(); i++)
|
||||
if (options.Commands[i].ActionSet.NeedScanning())
|
||||
needScanning = true;
|
||||
if (needScanning)
|
||||
{
|
||||
CEnumDirItemUpdateCallback enumCallback;
|
||||
enumCallback.Callback = callback;
|
||||
RINOK(callback->StartScanning());
|
||||
UStringVector errorPaths;
|
||||
CRecordVector<DWORD> errorCodes;
|
||||
HRESULT res = EnumerateItems(censor, dirItems, &enumCallback, errorPaths, errorCodes);
|
||||
for (int i = 0; i < errorPaths.Size(); i++)
|
||||
{
|
||||
RINOK(callback->CanNotFindError(errorPaths[i], errorCodes[i]));
|
||||
}
|
||||
if(res != S_OK)
|
||||
{
|
||||
errorInfo.Message = L"Scanning error";
|
||||
// errorInfo.FileName = errorPath;
|
||||
return res;
|
||||
}
|
||||
RINOK(callback->FinishScanning());
|
||||
}
|
||||
}
|
||||
|
||||
UString tempDirPrefix;
|
||||
bool usesTempDir = false;
|
||||
|
||||
#ifdef _WIN32
|
||||
NDirectory::CTempDirectoryW tempDirectory;
|
||||
if (options.EMailMode && options.EMailRemoveAfter)
|
||||
{
|
||||
tempDirectory.Create(kTempFolderPrefix);
|
||||
tempDirPrefix = tempDirectory.GetPath();
|
||||
NormalizeDirPathPrefix(tempDirPrefix);
|
||||
usesTempDir = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
CTempFiles tempFiles;
|
||||
|
||||
bool createTempFile = false;
|
||||
if(!options.StdOutMode && options.UpdateArchiveItself)
|
||||
{
|
||||
CArchivePath &ap = options.Commands[0].ArchivePath;
|
||||
ap = options.ArchivePath;
|
||||
// if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
|
||||
if ((archive != 0 || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
|
||||
{
|
||||
createTempFile = true;
|
||||
ap.Temp = true;
|
||||
if (!options.WorkingDir.IsEmpty())
|
||||
{
|
||||
ap.TempPrefix = options.WorkingDir;
|
||||
NormalizeDirPathPrefix(ap.TempPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < options.Commands.Size(); i++)
|
||||
{
|
||||
CArchivePath &ap = options.Commands[i].ArchivePath;
|
||||
if (usesTempDir)
|
||||
{
|
||||
// Check it
|
||||
ap.Prefix = tempDirPrefix;
|
||||
// ap.Temp = true;
|
||||
// ap.TempPrefix = tempDirPrefix;
|
||||
}
|
||||
if (i > 0 || !createTempFile)
|
||||
{
|
||||
const UString &path = ap.GetFinalPath();
|
||||
if (NFind::DoesFileExist(path))
|
||||
{
|
||||
errorInfo.SystemError = 0;
|
||||
errorInfo.Message = L"File already exists";
|
||||
errorInfo.FileName = path;
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CObjectVector<CArchiveItem> archiveItems;
|
||||
if (archive != NULL)
|
||||
{
|
||||
RINOK(EnumerateInArchiveItems(censor,
|
||||
archive, defaultItemName, archiveFileInfo, archiveItems));
|
||||
}
|
||||
|
||||
RINOK(UpdateWithItemLists(codecs, options, archive, archiveItems, dirItems,
|
||||
tempFiles, errorInfo, callback));
|
||||
|
||||
if (archive != NULL)
|
||||
{
|
||||
RINOK(archiveLink.Close());
|
||||
archiveLink.Release();
|
||||
}
|
||||
|
||||
tempFiles.Paths.Clear();
|
||||
if(createTempFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
CArchivePath &ap = options.Commands[0].ArchivePath;
|
||||
const UString &tempPath = ap.GetTempPath();
|
||||
if (archive != NULL)
|
||||
if (!NDirectory::DeleteFileAlways(archiveName))
|
||||
{
|
||||
errorInfo.SystemError = ::GetLastError();
|
||||
errorInfo.Message = L"delete file error";
|
||||
errorInfo.FileName = archiveName;
|
||||
return E_FAIL;
|
||||
}
|
||||
if (!NDirectory::MyMoveFile(tempPath, archiveName))
|
||||
{
|
||||
errorInfo.SystemError = ::GetLastError();
|
||||
errorInfo.Message = L"move file error";
|
||||
errorInfo.FileName = tempPath;
|
||||
errorInfo.FileName2 = archiveName;
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (options.EMailMode)
|
||||
{
|
||||
NDLL::CLibrary mapiLib;
|
||||
if (!mapiLib.Load(TEXT("Mapi32.dll")))
|
||||
{
|
||||
errorInfo.SystemError = ::GetLastError();
|
||||
errorInfo.Message = L"can not load Mapi32.dll";
|
||||
return E_FAIL;
|
||||
}
|
||||
LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)
|
||||
mapiLib.GetProcAddress("MAPISendDocuments");
|
||||
if (fnSend == 0)
|
||||
{
|
||||
errorInfo.SystemError = ::GetLastError();
|
||||
errorInfo.Message = L"can not find MAPISendDocuments function";
|
||||
return E_FAIL;
|
||||
}
|
||||
UStringVector fullPaths;
|
||||
int i;
|
||||
for(i = 0; i < options.Commands.Size(); i++)
|
||||
{
|
||||
CArchivePath &ap = options.Commands[i].ArchivePath;
|
||||
UString arcPath;
|
||||
if(!NFile::NDirectory::MyGetFullPathName(ap.GetFinalPath(), arcPath))
|
||||
{
|
||||
errorInfo.SystemError = ::GetLastError();
|
||||
return E_FAIL;
|
||||
}
|
||||
fullPaths.Add(arcPath);
|
||||
}
|
||||
CCurrentDirRestorer curDirRestorer;
|
||||
for(i = 0; i < fullPaths.Size(); i++)
|
||||
{
|
||||
UString arcPath = fullPaths[i];
|
||||
UString fileName = ExtractFileNameFromPath(arcPath);
|
||||
AString path = GetAnsiString(arcPath);
|
||||
AString name = GetAnsiString(fileName);
|
||||
// Warning!!! MAPISendDocuments function changes Current directory
|
||||
fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
// Update.h
|
||||
|
||||
#ifndef __UPDATE_H
|
||||
#define __UPDATE_H
|
||||
|
||||
#include "Common/Wildcard.h"
|
||||
#include "Windows/FileFind.h"
|
||||
#include "../../Archive/IArchive.h"
|
||||
|
||||
#include "UpdateAction.h"
|
||||
#include "ArchiveOpenCallback.h"
|
||||
#include "UpdateCallback.h"
|
||||
#include "Property.h"
|
||||
#include "LoadCodecs.h"
|
||||
|
||||
struct CArchivePath
|
||||
{
|
||||
UString Prefix; // path(folder) prefix including slash
|
||||
UString Name; // base name
|
||||
UString BaseExtension; // archive type extension or "exe" extension
|
||||
UString VolExtension; // archive type extension for volumes
|
||||
|
||||
bool Temp;
|
||||
UString TempPrefix; // path(folder) for temp location
|
||||
UString TempPostfix;
|
||||
|
||||
CArchivePath(): Temp(false) {};
|
||||
|
||||
void ParseFromPath(const UString &path)
|
||||
{
|
||||
SplitPathToParts(path, Prefix, Name);
|
||||
if (Name.IsEmpty())
|
||||
return;
|
||||
int dotPos = Name.ReverseFind(L'.');
|
||||
if (dotPos <= 0)
|
||||
return;
|
||||
if (dotPos == Name.Length() - 1)
|
||||
{
|
||||
Name = Name.Left(dotPos);
|
||||
BaseExtension.Empty();
|
||||
return;
|
||||
}
|
||||
if (BaseExtension.CompareNoCase(Name.Mid(dotPos + 1)) == 0)
|
||||
{
|
||||
BaseExtension = Name.Mid(dotPos + 1);
|
||||
Name = Name.Left(dotPos);
|
||||
}
|
||||
else
|
||||
BaseExtension.Empty();
|
||||
}
|
||||
|
||||
UString GetPathWithoutExt() const
|
||||
{
|
||||
return Prefix + Name;
|
||||
}
|
||||
|
||||
UString GetFinalPath() const
|
||||
{
|
||||
UString path = GetPathWithoutExt();
|
||||
if (!BaseExtension.IsEmpty())
|
||||
path += UString(L'.') + BaseExtension;
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
UString GetTempPath() const
|
||||
{
|
||||
UString path = TempPrefix + Name;
|
||||
if (!BaseExtension.IsEmpty())
|
||||
path += UString(L'.') + BaseExtension;
|
||||
path += L".tmp";
|
||||
path += TempPostfix;
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
struct CUpdateArchiveCommand
|
||||
{
|
||||
UString UserArchivePath;
|
||||
CArchivePath ArchivePath;
|
||||
NUpdateArchive::CActionSet ActionSet;
|
||||
};
|
||||
|
||||
struct CCompressionMethodMode
|
||||
{
|
||||
int FormatIndex;
|
||||
CObjectVector<CProperty> Properties;
|
||||
CCompressionMethodMode(): FormatIndex(-1) {}
|
||||
};
|
||||
|
||||
struct CUpdateOptions
|
||||
{
|
||||
CCompressionMethodMode MethodMode;
|
||||
|
||||
CObjectVector<CUpdateArchiveCommand> Commands;
|
||||
bool UpdateArchiveItself;
|
||||
CArchivePath ArchivePath;
|
||||
|
||||
bool SfxMode;
|
||||
UString SfxModule;
|
||||
|
||||
bool OpenShareForWrite;
|
||||
|
||||
bool StdInMode;
|
||||
UString StdInFileName;
|
||||
bool StdOutMode;
|
||||
|
||||
bool EMailMode;
|
||||
bool EMailRemoveAfter;
|
||||
UString EMailAddress;
|
||||
|
||||
UString WorkingDir;
|
||||
|
||||
bool Init(const CCodecs *codecs, const UString &arcPath, const UString &arcType);
|
||||
|
||||
CUpdateOptions():
|
||||
UpdateArchiveItself(true),
|
||||
SfxMode(false),
|
||||
StdInMode(false),
|
||||
StdOutMode(false),
|
||||
EMailMode(false),
|
||||
EMailRemoveAfter(false),
|
||||
OpenShareForWrite(false)
|
||||
{};
|
||||
CRecordVector<UInt64> VolumesSizes;
|
||||
};
|
||||
|
||||
struct CErrorInfo
|
||||
{
|
||||
DWORD SystemError;
|
||||
UString FileName;
|
||||
UString FileName2;
|
||||
UString Message;
|
||||
// UStringVector ErrorPaths;
|
||||
// CRecordVector<DWORD> ErrorCodes;
|
||||
CErrorInfo(): SystemError(0) {};
|
||||
};
|
||||
|
||||
struct CUpdateErrorInfo: public CErrorInfo
|
||||
{
|
||||
};
|
||||
|
||||
#define INTERFACE_IUpdateCallbackUI2(x) \
|
||||
INTERFACE_IUpdateCallbackUI(x) \
|
||||
virtual HRESULT OpenResult(const wchar_t *name, HRESULT result) x; \
|
||||
virtual HRESULT StartScanning() x; \
|
||||
virtual HRESULT CanNotFindError(const wchar_t *name, DWORD systemError) x; \
|
||||
virtual HRESULT FinishScanning() x; \
|
||||
virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \
|
||||
virtual HRESULT FinishArchive() x; \
|
||||
|
||||
struct IUpdateCallbackUI2: public IUpdateCallbackUI
|
||||
{
|
||||
INTERFACE_IUpdateCallbackUI2(=0)
|
||||
};
|
||||
|
||||
HRESULT UpdateArchive(
|
||||
CCodecs *codecs,
|
||||
const NWildcard::CCensor &censor,
|
||||
CUpdateOptions &options,
|
||||
CUpdateErrorInfo &errorInfo,
|
||||
IOpenCallbackUI *openCallback,
|
||||
IUpdateCallbackUI2 *callback);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
// UpdateAction.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "UpdateAction.h"
|
||||
|
||||
namespace NUpdateArchive {
|
||||
|
||||
const CActionSet kAddActionSet =
|
||||
{
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCompress,
|
||||
NPairAction::kCompress,
|
||||
NPairAction::kCompress,
|
||||
NPairAction::kCompress,
|
||||
NPairAction::kCompress
|
||||
};
|
||||
|
||||
const CActionSet kUpdateActionSet =
|
||||
{
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCompress,
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCompress,
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCompress
|
||||
};
|
||||
|
||||
const CActionSet kFreshActionSet =
|
||||
{
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kIgnore,
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCompress,
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCompress
|
||||
};
|
||||
|
||||
const CActionSet kSynchronizeActionSet =
|
||||
{
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kIgnore,
|
||||
NPairAction::kCompress,
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCompress,
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kCompress,
|
||||
};
|
||||
|
||||
const CActionSet kDeleteActionSet =
|
||||
{
|
||||
NPairAction::kCopy,
|
||||
NPairAction::kIgnore,
|
||||
NPairAction::kIgnore,
|
||||
NPairAction::kIgnore,
|
||||
NPairAction::kIgnore,
|
||||
NPairAction::kIgnore,
|
||||
NPairAction::kIgnore
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// UpdateAction.h
|
||||
|
||||
#ifndef __UPDATE_ACTION_H
|
||||
#define __UPDATE_ACTION_H
|
||||
|
||||
namespace NUpdateArchive {
|
||||
|
||||
namespace NPairState
|
||||
{
|
||||
const int kNumValues = 7;
|
||||
enum EEnum
|
||||
{
|
||||
kNotMasked = 0,
|
||||
kOnlyInArchive,
|
||||
kOnlyOnDisk,
|
||||
kNewInArchive,
|
||||
kOldInArchive,
|
||||
kSameFiles,
|
||||
kUnknowNewerFiles
|
||||
};
|
||||
}
|
||||
namespace NPairAction
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kIgnore = 0,
|
||||
kCopy,
|
||||
kCompress,
|
||||
kCompressAsAnti
|
||||
};
|
||||
}
|
||||
struct CActionSet
|
||||
{
|
||||
NPairAction::EEnum StateActions[NPairState::kNumValues];
|
||||
bool NeedScanning() const
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NPairState::kNumValues; i++)
|
||||
if (StateActions[i] == NPairAction::kCompress)
|
||||
return true;
|
||||
for (i = 1; i < NPairState::kNumValues; i++)
|
||||
if (StateActions[i] != NPairAction::kIgnore)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
extern const CActionSet kAddActionSet;
|
||||
extern const CActionSet kUpdateActionSet;
|
||||
extern const CActionSet kFreshActionSet;
|
||||
extern const CActionSet kSynchronizeActionSet;
|
||||
extern const CActionSet kDeleteActionSet;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
// UpdateCallback.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "UpdateCallback.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/ComTry.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../Common/FileStreams.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
CArchiveUpdateCallback::CArchiveUpdateCallback():
|
||||
Callback(0),
|
||||
ShareForWrite(false),
|
||||
StdInMode(false),
|
||||
DirItems(0),
|
||||
ArchiveItems(0),
|
||||
UpdatePairs(0)
|
||||
{}
|
||||
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
return Callback->SetTotal(size);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
return Callback->SetCompleted(completeValue);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
return Callback->SetRatioInfo(inSize, outSize);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
STATPROPSTG kProperties[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsFolder, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidLastAccessTime, VT_FILETIME},
|
||||
{ NULL, kpidCreationTime, VT_FILETIME},
|
||||
{ NULL, kpidLastWriteTime, VT_FILETIME},
|
||||
{ NULL, kpidAttributes, VT_UI4},
|
||||
{ NULL, kpidIsAnti, VT_BOOL}
|
||||
};
|
||||
*/
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
/*
|
||||
return CStatPropEnumerator::CreateEnumerator(kProperties,
|
||||
sizeof(kProperties) / sizeof(kProperties[0]), enumerator);
|
||||
*/
|
||||
}
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
|
||||
Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
RINOK(Callback->CheckBreak());
|
||||
const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
|
||||
if(newData != NULL)
|
||||
*newData = BoolToInt(updatePair.NewData);
|
||||
if(newProperties != NULL)
|
||||
*newProperties = BoolToInt(updatePair.NewProperties);
|
||||
if(indexInArchive != NULL)
|
||||
{
|
||||
if (updatePair.ExistInArchive)
|
||||
{
|
||||
if (ArchiveItems == 0)
|
||||
*indexInArchive = updatePair.ArchiveItemIndex;
|
||||
else
|
||||
*indexInArchive = (*ArchiveItems)[updatePair.ArchiveItemIndex].IndexInServer;
|
||||
}
|
||||
else
|
||||
*indexInArchive = UInt32(-1);
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
|
||||
NWindows::NCOM::CPropVariant propVariant;
|
||||
|
||||
if (propID == kpidIsAnti)
|
||||
{
|
||||
propVariant = updatePair.IsAnti;
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (updatePair.IsAnti)
|
||||
{
|
||||
switch(propID)
|
||||
{
|
||||
case kpidIsFolder:
|
||||
case kpidPath:
|
||||
break;
|
||||
case kpidSize:
|
||||
propVariant = (UInt64)0;
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
default:
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if(updatePair.ExistOnDisk)
|
||||
{
|
||||
const CDirItem &dirItem = (*DirItems)[updatePair.DirItemIndex];
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
propVariant = dirItem.Name;
|
||||
break;
|
||||
case kpidIsFolder:
|
||||
propVariant = dirItem.IsDirectory();
|
||||
break;
|
||||
case kpidSize:
|
||||
propVariant = dirItem.Size;
|
||||
break;
|
||||
case kpidAttributes:
|
||||
propVariant = dirItem.Attributes;
|
||||
break;
|
||||
case kpidLastAccessTime:
|
||||
propVariant = dirItem.LastAccessTime;
|
||||
break;
|
||||
case kpidCreationTime:
|
||||
propVariant = dirItem.CreationTime;
|
||||
break;
|
||||
case kpidLastWriteTime:
|
||||
propVariant = dirItem.LastWriteTime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (propID == kpidPath)
|
||||
{
|
||||
if (updatePair.NewNameIsDefined)
|
||||
{
|
||||
propVariant = updatePair.NewName;
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
if (updatePair.ExistInArchive && Archive)
|
||||
{
|
||||
UInt32 indexInArchive;
|
||||
if (ArchiveItems == 0)
|
||||
indexInArchive = updatePair.ArchiveItemIndex;
|
||||
else
|
||||
indexInArchive = (*ArchiveItems)[updatePair.ArchiveItemIndex].IndexInServer;
|
||||
return Archive->GetProperty(indexInArchive, propID, value);
|
||||
}
|
||||
}
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
const CUpdatePair2 &updatePair = (*UpdatePairs)[index];
|
||||
if(!updatePair.NewData)
|
||||
return E_FAIL;
|
||||
|
||||
RINOK(Callback->CheckBreak());
|
||||
RINOK(Callback->Finilize());
|
||||
|
||||
if(updatePair.IsAnti)
|
||||
{
|
||||
return Callback->GetStream((*ArchiveItems)[updatePair.ArchiveItemIndex].Name, true);
|
||||
}
|
||||
const CDirItem &dirItem = (*DirItems)[updatePair.DirItemIndex];
|
||||
RINOK(Callback->GetStream(dirItem.Name, false));
|
||||
|
||||
if(dirItem.IsDirectory())
|
||||
return S_OK;
|
||||
|
||||
if (StdInMode)
|
||||
{
|
||||
CStdInFileStream *inStreamSpec = new CStdInFileStream;
|
||||
CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
|
||||
*inStream = inStreamLoc.Detach();
|
||||
}
|
||||
else
|
||||
{
|
||||
CInFileStream *inStreamSpec = new CInFileStream;
|
||||
CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
|
||||
UString path = DirPrefix + dirItem.FullPath;
|
||||
if(!inStreamSpec->OpenShared(path, ShareForWrite))
|
||||
{
|
||||
return Callback->OpenFileError(path, ::GetLastError());
|
||||
}
|
||||
*inStream = inStreamLoc.Detach();
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 operationResult)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
return Callback->SetOperationResult(operationResult);
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
|
||||
{
|
||||
if (VolumesSizes.Size() == 0)
|
||||
return S_FALSE;
|
||||
if (index >= (UInt32)VolumesSizes.Size())
|
||||
index = VolumesSizes.Size() - 1;
|
||||
*size = VolumesSizes[index];
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
wchar_t temp[32];
|
||||
ConvertUInt64ToString(index + 1, temp);
|
||||
UString res = temp;
|
||||
while (res.Length() < 2)
|
||||
res = UString(L'0') + res;
|
||||
UString fileName = VolName;
|
||||
fileName += L'.';
|
||||
fileName += res;
|
||||
fileName += VolExt;
|
||||
COutFileStream *streamSpec = new COutFileStream;
|
||||
CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
|
||||
if(!streamSpec->Create(fileName, false))
|
||||
return ::GetLastError();
|
||||
*volumeStream = streamLoc.Detach();
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
|
||||
COM_TRY_END
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// UpdateCallback.h
|
||||
|
||||
#ifndef __UPDATECALLBACK_H
|
||||
#define __UPDATECALLBACK_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "Common/MyString.h"
|
||||
|
||||
#include "../../IPassword.h"
|
||||
#include "../../ICoder.h"
|
||||
|
||||
#include "../Common/UpdatePair.h"
|
||||
#include "../Common/UpdateProduce.h"
|
||||
|
||||
#define INTERFACE_IUpdateCallbackUI(x) \
|
||||
virtual HRESULT SetTotal(UInt64 size) x; \
|
||||
virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \
|
||||
virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x; \
|
||||
virtual HRESULT CheckBreak() x; \
|
||||
virtual HRESULT Finilize() x; \
|
||||
virtual HRESULT SetNumFiles(UInt64 numFiles) x; \
|
||||
virtual HRESULT GetStream(const wchar_t *name, bool isAnti) x; \
|
||||
virtual HRESULT OpenFileError(const wchar_t *name, DWORD systemError) x; \
|
||||
virtual HRESULT SetOperationResult(Int32 operationResult) x; \
|
||||
virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \
|
||||
|
||||
// virtual HRESULT CloseProgress() { return S_OK; };
|
||||
|
||||
struct IUpdateCallbackUI
|
||||
{
|
||||
INTERFACE_IUpdateCallbackUI(=0)
|
||||
};
|
||||
|
||||
class CArchiveUpdateCallback:
|
||||
public IArchiveUpdateCallback2,
|
||||
public ICryptoGetTextPassword2,
|
||||
public ICompressProgressInfo,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP3(
|
||||
IArchiveUpdateCallback2,
|
||||
ICryptoGetTextPassword2,
|
||||
ICompressProgressInfo)
|
||||
|
||||
// IProgress
|
||||
STDMETHOD(SetTotal)(UInt64 size);
|
||||
STDMETHOD(SetCompleted)(const UInt64 *completeValue);
|
||||
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
|
||||
|
||||
// IUpdateCallback
|
||||
STDMETHOD(EnumProperties)(IEnumSTATPROPSTG **enumerator);
|
||||
STDMETHOD(GetUpdateItemInfo)(UInt32 index,
|
||||
Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive);
|
||||
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
|
||||
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream);
|
||||
STDMETHOD(SetOperationResult)(Int32 operationResult);
|
||||
|
||||
STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size);
|
||||
STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream);
|
||||
|
||||
STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
|
||||
|
||||
public:
|
||||
CRecordVector<UInt64> VolumesSizes;
|
||||
UString VolName;
|
||||
UString VolExt;
|
||||
|
||||
IUpdateCallbackUI *Callback;
|
||||
|
||||
UString DirPrefix;
|
||||
bool ShareForWrite;
|
||||
bool StdInMode;
|
||||
const CObjectVector<CDirItem> *DirItems;
|
||||
const CObjectVector<CArchiveItem> *ArchiveItems;
|
||||
const CObjectVector<CUpdatePair2> *UpdatePairs;
|
||||
CMyComPtr<IInArchive> Archive;
|
||||
|
||||
CArchiveUpdateCallback();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,166 @@
|
||||
// UpdatePair.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/Wildcard.h"
|
||||
#include "Windows/Time.h"
|
||||
|
||||
#include "UpdatePair.h"
|
||||
#include "SortUtils.h"
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NTime;
|
||||
|
||||
static int MyCompareTime(NFileTimeType::EEnum fileTimeType,
|
||||
const FILETIME &time1, const FILETIME &time2)
|
||||
{
|
||||
switch(fileTimeType)
|
||||
{
|
||||
case NFileTimeType::kWindows:
|
||||
return ::CompareFileTime(&time1, &time2);
|
||||
case NFileTimeType::kUnix:
|
||||
{
|
||||
UInt32 unixTime1, unixTime2;
|
||||
if (!FileTimeToUnixTime(time1, unixTime1))
|
||||
{
|
||||
unixTime1 = 0;
|
||||
// throw 4191614;
|
||||
}
|
||||
if (!FileTimeToUnixTime(time2, unixTime2))
|
||||
{
|
||||
unixTime2 = 0;
|
||||
// throw 4191615;
|
||||
}
|
||||
return MyCompare(unixTime1, unixTime2);
|
||||
}
|
||||
case NFileTimeType::kDOS:
|
||||
{
|
||||
UInt32 dosTime1, dosTime2;
|
||||
FileTimeToDosTime(time1, dosTime1);
|
||||
FileTimeToDosTime(time2, dosTime2);
|
||||
/*
|
||||
if (!FileTimeToDosTime(time1, dosTime1))
|
||||
throw 4191616;
|
||||
if (!FileTimeToDosTime(time2, dosTime2))
|
||||
throw 4191617;
|
||||
*/
|
||||
return MyCompare(dosTime1, dosTime2);
|
||||
}
|
||||
}
|
||||
throw 4191618;
|
||||
}
|
||||
|
||||
static const wchar_t *kDuplicateFileNameMessage = L"Duplicate filename:";
|
||||
|
||||
/*
|
||||
static const char *kNotCensoredCollisionMessaged = "Internal file name collision:\n";
|
||||
static const char *kSameTimeChangedSizeCollisionMessaged =
|
||||
"Collision between files with same date/time and different sizes:\n";
|
||||
*/
|
||||
|
||||
static void TestDuplicateString(const UStringVector &strings, const CIntVector &indices)
|
||||
{
|
||||
for(int i = 0; i + 1 < indices.Size(); i++)
|
||||
if (CompareFileNames(strings[indices[i]], strings[indices[i + 1]]) == 0)
|
||||
{
|
||||
UString message = kDuplicateFileNameMessage;
|
||||
message += L"\n";
|
||||
message += strings[indices[i]];
|
||||
message += L"\n";
|
||||
message += strings[indices[i + 1]];
|
||||
throw message;
|
||||
}
|
||||
}
|
||||
|
||||
void GetUpdatePairInfoList(
|
||||
const CObjectVector<CDirItem> &dirItems,
|
||||
const CObjectVector<CArchiveItem> &archiveItems,
|
||||
NFileTimeType::EEnum fileTimeType,
|
||||
CObjectVector<CUpdatePair> &updatePairs)
|
||||
{
|
||||
CIntVector dirIndices, archiveIndices;
|
||||
UStringVector dirNames, archiveNames;
|
||||
|
||||
int numDirItems = dirItems.Size();
|
||||
int i;
|
||||
for(i = 0; i < numDirItems; i++)
|
||||
dirNames.Add(dirItems[i].Name);
|
||||
SortFileNames(dirNames, dirIndices);
|
||||
TestDuplicateString(dirNames, dirIndices);
|
||||
|
||||
int numArchiveItems = archiveItems.Size();
|
||||
for(i = 0; i < numArchiveItems; i++)
|
||||
archiveNames.Add(archiveItems[i].Name);
|
||||
SortFileNames(archiveNames, archiveIndices);
|
||||
TestDuplicateString(archiveNames, archiveIndices);
|
||||
|
||||
int dirItemIndex = 0, archiveItemIndex = 0;
|
||||
CUpdatePair pair;
|
||||
while(dirItemIndex < numDirItems && archiveItemIndex < numArchiveItems)
|
||||
{
|
||||
int dirItemIndex2 = dirIndices[dirItemIndex],
|
||||
archiveItemIndex2 = archiveIndices[archiveItemIndex];
|
||||
const CDirItem &dirItem = dirItems[dirItemIndex2];
|
||||
const CArchiveItem &archiveItem = archiveItems[archiveItemIndex2];
|
||||
int compareResult = CompareFileNames(dirItem.Name, archiveItem.Name);
|
||||
if (compareResult < 0)
|
||||
{
|
||||
pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
|
||||
pair.DirItemIndex = dirItemIndex2;
|
||||
dirItemIndex++;
|
||||
}
|
||||
else if (compareResult > 0)
|
||||
{
|
||||
pair.State = archiveItem.Censored ?
|
||||
NUpdateArchive::NPairState::kOnlyInArchive: NUpdateArchive::NPairState::kNotMasked;
|
||||
pair.ArchiveItemIndex = archiveItemIndex2;
|
||||
archiveItemIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!archiveItem.Censored)
|
||||
throw 1082022;; // TTString(kNotCensoredCollisionMessaged + dirItem.Name);
|
||||
pair.DirItemIndex = dirItemIndex2;
|
||||
pair.ArchiveItemIndex = archiveItemIndex2;
|
||||
switch (MyCompareTime(fileTimeType, dirItem.LastWriteTime, archiveItem.LastWriteTime))
|
||||
{
|
||||
case -1:
|
||||
pair.State = NUpdateArchive::NPairState::kNewInArchive;
|
||||
break;
|
||||
case 1:
|
||||
pair.State = NUpdateArchive::NPairState::kOldInArchive;
|
||||
break;
|
||||
default:
|
||||
if (archiveItem.SizeIsDefined)
|
||||
if (dirItem.Size != archiveItem.Size)
|
||||
// throw 1082034; // kSameTimeChangedSizeCollisionMessaged;
|
||||
pair.State = NUpdateArchive::NPairState::kUnknowNewerFiles;
|
||||
else
|
||||
pair.State = NUpdateArchive::NPairState::kSameFiles;
|
||||
else
|
||||
pair.State = NUpdateArchive::NPairState::kUnknowNewerFiles;
|
||||
}
|
||||
dirItemIndex++;
|
||||
archiveItemIndex++;
|
||||
}
|
||||
updatePairs.Add(pair);
|
||||
}
|
||||
for(;dirItemIndex < numDirItems; dirItemIndex++)
|
||||
{
|
||||
pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
|
||||
pair.DirItemIndex = dirIndices[dirItemIndex];
|
||||
updatePairs.Add(pair);
|
||||
}
|
||||
for(;archiveItemIndex < numArchiveItems; archiveItemIndex++)
|
||||
{
|
||||
int archiveItemIndex2 = archiveIndices[archiveItemIndex];
|
||||
const CArchiveItem &archiveItem = archiveItems[archiveItemIndex2];
|
||||
pair.State = archiveItem.Censored ?
|
||||
NUpdateArchive::NPairState::kOnlyInArchive: NUpdateArchive::NPairState::kNotMasked;
|
||||
pair.ArchiveItemIndex = archiveItemIndex2;
|
||||
updatePairs.Add(pair);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// UpdatePair.h
|
||||
|
||||
#ifndef __UPDATE_PAIR_H
|
||||
#define __UPDATE_PAIR_H
|
||||
|
||||
#include "DirItem.h"
|
||||
#include "UpdateAction.h"
|
||||
|
||||
#include "../../Archive/IArchive.h"
|
||||
|
||||
struct CUpdatePair
|
||||
{
|
||||
NUpdateArchive::NPairState::EEnum State;
|
||||
int ArchiveItemIndex;
|
||||
int DirItemIndex;
|
||||
};
|
||||
|
||||
void GetUpdatePairInfoList(
|
||||
const CObjectVector<CDirItem> &dirItems,
|
||||
const CObjectVector<CArchiveItem> &archiveItems,
|
||||
NFileTimeType::EEnum fileTimeType,
|
||||
CObjectVector<CUpdatePair> &updatePairs);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
// UpdateProduce.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "UpdateProduce.h"
|
||||
|
||||
using namespace NUpdateArchive;
|
||||
|
||||
static const char *kUpdateActionSetCollision =
|
||||
"Internal collision in update action set";
|
||||
|
||||
void UpdateProduce(
|
||||
const CObjectVector<CUpdatePair> &updatePairs,
|
||||
const NUpdateArchive::CActionSet &actionSet,
|
||||
CObjectVector<CUpdatePair2> &operationChain)
|
||||
{
|
||||
for(int i = 0; i < updatePairs.Size(); i++)
|
||||
{
|
||||
// CUpdateArchiveRange aRange;
|
||||
const CUpdatePair &pair = updatePairs[i];
|
||||
|
||||
CUpdatePair2 pair2;
|
||||
pair2.IsAnti = false;
|
||||
pair2.ArchiveItemIndex = pair.ArchiveItemIndex;
|
||||
pair2.DirItemIndex = pair.DirItemIndex;
|
||||
pair2.ExistInArchive = (pair.State != NPairState::kOnlyOnDisk);
|
||||
pair2.ExistOnDisk = (pair.State != NPairState::kOnlyInArchive && pair.State != NPairState::kNotMasked);
|
||||
switch(actionSet.StateActions[pair.State])
|
||||
{
|
||||
case NPairAction::kIgnore:
|
||||
/*
|
||||
if (pair.State != NPairState::kOnlyOnDisk)
|
||||
IgnoreArchiveItem(m_ArchiveItems[pair.ArchiveItemIndex]);
|
||||
// cout << "deleting";
|
||||
*/
|
||||
break;
|
||||
case NPairAction::kCopy:
|
||||
{
|
||||
if (pair.State == NPairState::kOnlyOnDisk)
|
||||
throw kUpdateActionSetCollision;
|
||||
pair2.NewData = pair2.NewProperties = false;
|
||||
operationChain.Add(pair2);
|
||||
break;
|
||||
}
|
||||
case NPairAction::kCompress:
|
||||
{
|
||||
if (pair.State == NPairState::kOnlyInArchive ||
|
||||
pair.State == NPairState::kNotMasked)
|
||||
throw kUpdateActionSetCollision;
|
||||
pair2.NewData = pair2.NewProperties = true;
|
||||
operationChain.Add(pair2);
|
||||
break;
|
||||
}
|
||||
case NPairAction::kCompressAsAnti:
|
||||
{
|
||||
pair2.IsAnti = true;
|
||||
pair2.NewData = pair2.NewProperties = true;
|
||||
operationChain.Add(pair2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// UpdateProduce.h
|
||||
|
||||
#ifndef __UPDATE_PRODUCE_H
|
||||
#define __UPDATE_PRODUCE_H
|
||||
|
||||
#include "UpdatePair.h"
|
||||
|
||||
struct CUpdatePair2
|
||||
{
|
||||
// bool OperationIsCompress;
|
||||
bool NewData;
|
||||
bool NewProperties;
|
||||
|
||||
bool ExistInArchive;
|
||||
bool ExistOnDisk;
|
||||
bool IsAnti;
|
||||
int ArchiveItemIndex;
|
||||
int DirItemIndex;
|
||||
|
||||
bool NewNameIsDefined;
|
||||
UString NewName;
|
||||
|
||||
CUpdatePair2(): NewNameIsDefined(false) {}
|
||||
};
|
||||
|
||||
void UpdateProduce(
|
||||
const CObjectVector<CUpdatePair> &updatePairs,
|
||||
const NUpdateArchive::CActionSet &actionSet,
|
||||
CObjectVector<CUpdatePair2> &operationChain);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
// WorkDir.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "WorkDir.h"
|
||||
|
||||
#include "Common/StringConvert.h"
|
||||
#include "Common/Wildcard.h"
|
||||
|
||||
#include "Windows/FileName.h"
|
||||
#include "Windows/FileDir.h"
|
||||
|
||||
static inline UINT GetCurrentCodePage()
|
||||
{ return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; }
|
||||
|
||||
using namespace NWindows;
|
||||
using namespace NFile;
|
||||
using namespace NName;
|
||||
|
||||
UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path)
|
||||
{
|
||||
NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
|
||||
if (workDirInfo.ForRemovableOnly)
|
||||
{
|
||||
mode = NWorkDir::NMode::kCurrent;
|
||||
UString prefix = path.Left(3);
|
||||
if (prefix[1] == L':' && prefix[2] == L'\\')
|
||||
{
|
||||
UINT driveType = GetDriveType(GetSystemString(prefix, GetCurrentCodePage()));
|
||||
if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE)
|
||||
mode = workDirInfo.Mode;
|
||||
}
|
||||
/*
|
||||
CParsedPath parsedPath;
|
||||
parsedPath.ParsePath(archiveName);
|
||||
UINT driveType = GetDriveType(parsedPath.Prefix);
|
||||
if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE))
|
||||
mode = NZipSettings::NWorkDir::NMode::kCurrent;
|
||||
*/
|
||||
}
|
||||
switch(mode)
|
||||
{
|
||||
case NWorkDir::NMode::kCurrent:
|
||||
{
|
||||
return ExtractDirPrefixFromPath(path);
|
||||
}
|
||||
case NWorkDir::NMode::kSpecified:
|
||||
{
|
||||
UString tempDir = workDirInfo.Path;
|
||||
NormalizeDirPathPrefix(tempDir);
|
||||
return tempDir;
|
||||
}
|
||||
default:
|
||||
{
|
||||
UString tempDir;
|
||||
if(!NFile::NDirectory::MyGetTempPath(tempDir))
|
||||
throw 141717;
|
||||
return tempDir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// WorkDir.h
|
||||
|
||||
#ifndef __WORKDIR_H
|
||||
#define __WORKDIR_H
|
||||
|
||||
#include "ZipRegistry.h"
|
||||
|
||||
UString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const UString &path);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
// ZipRegistry.h
|
||||
|
||||
#ifndef __ZIPREGISTRY_H
|
||||
#define __ZIPREGISTRY_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
#include "Common/Types.h"
|
||||
#include "ExtractMode.h"
|
||||
|
||||
namespace NExtract
|
||||
{
|
||||
struct CInfo
|
||||
{
|
||||
NPathMode::EEnum PathMode;
|
||||
NOverwriteMode::EEnum OverwriteMode;
|
||||
UStringVector Paths;
|
||||
bool ShowPassword;
|
||||
};
|
||||
}
|
||||
|
||||
namespace NCompression {
|
||||
|
||||
struct CFormatOptions
|
||||
{
|
||||
CSysString FormatID;
|
||||
UString Options;
|
||||
UString Method;
|
||||
UString EncryptionMethod;
|
||||
UInt32 Level;
|
||||
UInt32 Dictionary;
|
||||
UInt32 Order;
|
||||
UInt32 BlockLogSize;
|
||||
UInt32 NumThreads;
|
||||
void ResetForLevelChange()
|
||||
{
|
||||
BlockLogSize = NumThreads = Level = Dictionary = Order = UInt32(-1);
|
||||
Method.Empty();
|
||||
// EncryptionMethod.Empty();
|
||||
// Options.Empty();
|
||||
}
|
||||
CFormatOptions() { ResetForLevelChange(); }
|
||||
};
|
||||
|
||||
struct CInfo
|
||||
{
|
||||
UStringVector HistoryArchives;
|
||||
UInt32 Level;
|
||||
UString ArchiveType;
|
||||
|
||||
CObjectVector<CFormatOptions> FormatOptionsVector;
|
||||
|
||||
bool ShowPassword;
|
||||
bool EncryptHeaders;
|
||||
};
|
||||
}
|
||||
|
||||
namespace NWorkDir{
|
||||
|
||||
namespace NMode
|
||||
{
|
||||
enum EEnum
|
||||
{
|
||||
kSystem,
|
||||
kCurrent,
|
||||
kSpecified
|
||||
};
|
||||
}
|
||||
struct CInfo
|
||||
{
|
||||
NMode::EEnum Mode;
|
||||
UString Path;
|
||||
bool ForRemovableOnly;
|
||||
void SetForRemovableOnlyDefault() { ForRemovableOnly = true; }
|
||||
void SetDefault()
|
||||
{
|
||||
Mode = NMode::kSystem;
|
||||
Path.Empty();
|
||||
SetForRemovableOnlyDefault();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void SaveExtractionInfo(const NExtract::CInfo &info);
|
||||
void ReadExtractionInfo(NExtract::CInfo &info);
|
||||
|
||||
void SaveCompressionInfo(const NCompression::CInfo &info);
|
||||
void ReadCompressionInfo(NCompression::CInfo &info);
|
||||
|
||||
void SaveWorkDirInfo(const NWorkDir::CInfo &info);
|
||||
void ReadWorkDirInfo(NWorkDir::CInfo &info);
|
||||
|
||||
void SaveCascadedMenu(bool enabled);
|
||||
bool ReadCascadedMenu();
|
||||
|
||||
void SaveContextMenuStatus(UInt32 value);
|
||||
bool ReadContextMenuStatus(UInt32 &value);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user